测试是软件项目的重要组成部分,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.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
就演示了这一功能。
代码清单5-4 测试
ReadingListController
的Spock说明
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是如何帮助产生一个可部署的产物的。