Spring Boot可以和大部分流行的测试框架协同工作:通过Spring JUnit创建单元测试;生成测试数据初始化数据库用于测试;Spring Boot可以跟BDD(Behavier Driven Development)工具、Cucumber和Spock协同工作,对应用程序进行测试。
进行软件开发的时候,我们会写很多代码,不过,再过六个月(甚至一年以上)你知道自己的代码怎么运作么?通过测试(单元测试、集成测试、接口测试)可以保证系统的可维护性,当我们修改了某些代码时,通过回归测试可以检查是否引入了新的bug。总得来说,测试让系统不再是一个黑盒子,让开发人员确认系统可用。
在web应用程序中,对Controller层的测试一般有两种方法:(1)发送http请求;(2)模拟http请求对象。第一种方法需要配置回归环境,通过修改代码统计的策略来计算覆盖率;第二种方法是比较正规的思路,但是在我目前经历过的项目中用得不多,今天总结下如何用Mock对象测试Controller层的代码。
在之前的几篇文章中,我们都使用bookpub这个应用程序作为例子,今天也不例外,准备测试它提供的RESTful接口是否能返回正确的响应数据。这种测试不同于单元测试,需要为之初始化完整的应用程序上下文、所有的spring bean都织入以及数据库中需要有测试数据,一般来说这种测试称之为集成测试或者接口测试。
实战通过spirng.io新建的Spring Boot项目提供了一个空的测试文件——BookPubApplicationTest.java,内容是:
@RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = BookPubApplication.class) public class BookPubApplicationTests { @Test public void contextLoads() { } }在pom文件中增加spring-boot-starter-test依赖,添加jsonPath依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.jayway.jsonpath</groupId> <artifactId>json-path</artifactId> </dependency>在BookPubApplicationTest中添加测试用例
package com.test.bookpub; import com.test.bookpub.domain.Book; import com.test.bookpub.repository.BookRepository; import org.junit.Before;import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.SpringApplicationConfiguration; import org.springframework.boot.test.TestRestTemplate; import org.springframework.boot.test.WebIntegrationTest; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.client.RestTemplate; import org.springframework.web.context.WebApplicationContext; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.hamcrest.Matchers.containsString; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = BookPubApplication.class) @WebIntegrationTest("server.port:0") public class BookPubApplicationTests { @Autowired private WebApplicationContext context; @Autowired private BookRepository bookRepository; @Value("${local.server.port}") private int port; private MockMvc mockMvc; private RestTemplate restTemplate = new TestRestTemplate(); @Before public void setupMockMvc() { mockMvc = MockMvcBuilders.webAppContextSetup(context).build(); } @Test public void contextLoads() { assertEquals(1, bookRepository.count()); } @Test public void webappBookIsbnApi() { Book book = restTemplate.getForObject("http://localhost:" + port +"/books/9876-5432-1111", Book.class); assertNotNull(book); assertEquals("中文测试", book.getPublisher().getName()); } @Test public void webappPublisherApi() throws Exception { //MockHttpServletRequestBuilder.accept方法是设置客户端可识别的内容类型 //MockHttpServletRequestBuilder.contentType,设置请求头中的Content-Type字段,表示请求体的内容类型 mockMvc.perform(get("/publishers/1") .accept(MediaType.APPLICATION_JSON_UTF8)) .andExpect(status().isOk()) .andExpect(content().string(containsString("中文测试"))) .andExpect(jsonPath("$.name").value("中文测试")); } }spring boot项目的代码覆盖率
使用cobertura,参考项目的github地址:spring boot template