用CLI运行测试
测试是软件项目的重要组成部分,Spring Boot CLI 当然没有忽略测试。因为基于 CLI 的应用程序并未涉及传统的构建系统,所以 CLI 提供了一个 test 命令来运行测试。
在试验 test 命令前,你先要写一个测试。测试可以放在项目中的任何位置。我建议将其与主要组件分开放置,最好放在一个子目录里。这个子目录的名字随意。我在这里将其命名为 tests:
$ mkdir tests
在 tests 目录里,创建一个名为 ReadingListControllerTest.groovy 的新 Groovy 脚本,编写针对 ReadingListController 的测试。代码清单5-3是个简单的测试,测试控制器能否正确处理 HTTP GET 请求。
import org.springframework.test.web.servlet.MockMvc
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
import static org.mockito.Mockito.*
class ReadingListControllerTest {
@Test
void shouldReturnReadingListFromRepository() {
List<Book> expectedList = new ArrayList<Book>()
expectedList.add(new Book(
id: 1,
reader: "Craig",
isbn: "9781617292545",
title: "Spring Boot in Action",
author: "Craig Walls",
description: "Spring Boot in Action is ..."
))
def mockRepo = mock(ReadingListRepository.class) // 模拟ReadingListRepository
when(mockRepo.findByReader("Craig")).thenReturn(expectedList)
def controller = new ReadingListController(readingListRepository: mockRepo)
MockMvc mvc = standaloneSetup(controller)
.build()
mvc.perform(get("/")) // 执行并测试GET请求
.andExpect(view().name("readingList"))
.andExpect(model().attribute("books", expectedList))
}
}
如你所见,这就是个简单的 JUnit 测试,使用了 Spring 的模拟 MVC 测试支持功能,对控制器发起 GET 请求。最先设置的是 ReadingListRepository 的一个模拟实现,它会返回一个包含单一Book 项的列表。随后,测试创建了一个 ReadingListController 实例,将模拟仓库注入 readingListRepository 属性。最后,配置了一个 MockMvc 对象,发起 GET 请求,对期望的视图名称和模型内容进行断言。
但是,此处运行测试要比说明测试更重要。使用 CLI 的 test 命令,可以像下面这样在命令行里执行测试:
$ spring test tests/ReadingListControllerTest.groovy
本例中,我明确选中了 ReadingListControllerTest 作为要运行的测试。如果 tests/ 目录里有多个测试,你想要全部运行,可以在 test 命令中指定目录名:
$ spring test tests
如果你倾向于编写 Spock 说明而非 JUnit 测试,那么你一定会很高兴,因为 CLI 的 test 命令也可以运行 Spock 说明,代码清单5-4的 ReadingListControllerSpec 就演示了这一功能。
import org.springframework.test.web.servlet.MockMvc
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*
import static org.mockito.Mockito.*
class ReadingListControllerSpec extends Specification {
MockMvc mockMvc
List<Book> expectedList
def setup() {
expectedList = new ArrayList<Book>()
expectedList.add(new Book(
id: 1,
reader: "Craig",
isbn: "9781617292545",
title: "Spring Boot in Action",
author: "Craig Walls",
description: "Spring Boot in Action is ..."
))
def mockRepo = mock(ReadingListRepository.class) // 模拟的 ReadingListRepository
when(mockRepo.findByReader("Craig")).thenReturn(expectedList)
def controller =
new ReadingListController(readingListRepository: mockRepo)
mockMvc = standaloneSetup(controller).build()
}
def "Should put list returned from repository into model"() {
when:
def response = mockMvc.perform(get("/")) // 执行GET请求
then:
response.andExpect(view().name("readingList"))
.andExpect(model().attribute("books", expectedList)) // 测试结果
}
}
ReadingListControllerSpec 只是简单地把 ReadingListControllerTest 从 JUnit 测试翻译成了 Spock 说明。如你所见,它只是直白地表述了这么一个过程。对 “/” 出现 GET 请求时,响应中应该包含名为 readingList 的视图。模型里的 books 键所对应的就是期待的图书列表。
Spock 说明也可以通过 spring test tests 来运行 ReadingListControllerSpec。运行方式和基于 JUnit 的测试如出一辙。
一旦写好代码,通过了全部测试,你就该部署项目了。让我们来看看 Spring Boot CLI 是如何帮助产生一个可部署的产物的。