测试是软件项目的重要组成部分,Spring Boot CLI当然没有忽略测试。因为基于CLI的应用程序并未涉及传统的构建系统,所以CLI提供了一个test
命令来运行测试。
在试验test
命令前,你先要写一个测试。测试可以放在项目中的任何位置。我建议将其与主要组件分开放置,最好放在一个子目录里。这个子目录的名字随意。我在这里将其命名为tests:
$ mkdir tests
在tests目录里,创建一个名为ReadingListControllerTest.groovy的新Groovy脚本,编写针对ReadingListController
的测试。代码清单5-3是个简单的测试,测试控制器能否正确处理HTTP GET
请求。
代码清单5-3
ReadingListController
的Groovy测试
import org.springframework.test.web.servlet.MockMvcimport 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
就演示了这一功能。
代码清单5-4 测试
ReadingListController
的Spock说明
import org.springframework.test.web.servlet.MockMvcimport 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是如何帮助产生一个可部署的产物的。