SpringBoot教程&笔记|Demo02-添加单元测试
- 一、单元测试的目的
- 二、添加单元测试
- 添加依赖
- 编写测试
- 三、执行单元测试
- 四、补充说明
- RequestBuilder/MockMvcRequestBuilders
- MockMvcRequestBuilders主要API
- MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder API
- ResultActions
- ResultMatcher/MockMvcResultMatchers
本教程在Demo01基础上添加测试方法
一、单元测试的目的
简单来说就是在我们增加或者改动一些代码以后对所有逻辑的一个检测,尤其是在我们后期修改后(不论是增加新功能,修改bug),都可以做到重新测试的工作。以减少我们在发布的时候出现更过甚至是出现之前解决了的问题再次重现。
这里主要是使用MockMvc对我们的系统的Controller进行单元测试。
对数据库的操作使用事务实现回滚,及对数据库的增删改方法结束后将会还原数据库。
二、添加单元测试
您需要为您添加的端点添加测试,Spring Test已经为此提供了一些机制,并且很容易将其包括在项目中。
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
编写测试
现在编写一个简单的单元测试,通过端点模拟servlet请求和响应:
src/test/java/com/heardfate/springboot/demo/controller/HelloControllerTest.java
package com.heardfate.springboot.demo.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/**
* @since: 2018/10/20
* @author: Mr.HeardFate
*/
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/")//请求的url,请求的方法是get
.accept(MediaType.APPLICATION_JSON))//指定请求的Accept头信息
.andDo(print())//打印出请求和相应的内容
.andExpect(status().isOk())//返回的状态是200
.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
}
}
三、执行单元测试
在HelloControllerTest.java
右击Run即可
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.1.0.RC1)
2018-10-20 08:55:17.691 INFO 1223 --- [ main] c.h.s.d.controller.HelloControllerTest : Starting HelloControllerTest on heardfatedeMac-Pro.local with PID 1223 (started by **** in /****/IdeaProjects/springboot-demo/demo01)
2018-10-20 08:55:17.694 INFO 1223 --- [ main] c.h.s.d.controller.HelloControllerTest : No active profile set, falling back to default profiles: default
2018-10-20 08:55:19.283 INFO 1223 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2018-10-20 08:55:20.491 INFO 1223 --- [ main] o.s.b.t.m.w.SpringBootMockServletContext : Initializing Spring TestDispatcherServlet ''
2018-10-20 08:55:20.491 INFO 1223 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Initializing Servlet ''
2018-10-20 08:55:20.514 INFO 1223 --- [ main] o.s.t.web.servlet.TestDispatcherServlet : Completed initialization in 23 ms
2018-10-20 08:55:20.578 INFO 1223 --- [ main] c.h.s.d.controller.HelloControllerTest : Started HelloControllerTest in 8.326 seconds (JVM running for 9.627)
MockHttpServletRequest:
HTTP Method = GET
Request URI = /
Parameters = {}
Headers = {Accept=[application/json]}
Body = null
Session Attrs = {}
Handler:
Type = com.heardfate.springboot.demo.controller.HelloController
Method = public java.lang.String com.heardfate.springboot.demo.controller.HelloController.index()
Async:
Async started = false
Async result = null
Resolved Exception:
Type = null
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 200
Error message = null
Headers = {Content-Type=[application/json;charset=UTF-8], Content-Length=[27]}
Content type = application/json;charset=UTF-8
Body = Greetings from Spring Boot!
Forwarded URL = null
Redirected URL = null
Cookies = []
2018-10-20 08:55:21.067 INFO 1223 --- [ Thread-2] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
Process finished with exit code 0
四、补充说明
@RunWith(SpringRunner.class)
: 表示使用Spring Test组件进行单元测试;@SpringBootTest
: 使用@SpringBootTest加载测试的spring上下文环境;@AutoConfigureMockMvc
: 自动配置MockMvc这个类
RequestBuilder/MockMvcRequestBuilders
从名字可以看出,RequestBuilder用来构建请求的,其提供了一个方法buildRequest(ServletContext servletContext)用于构建MockHttpServletRequest;其主要有两个子类MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder(如文件上传使用),即用来Mock客户端请求需要的所有数据。
MockMvcRequestBuilders
主要API
MockHttpServletRequestBuilder get(String urlTemplate, Object… urlVariables)
:根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder;如get(/user/{id}, 1L);
MockHttpServletRequestBuilder post(String urlTemplate, Object… urlVariables)
:同get类似,但是是POST方法;提供自己的Http请求方法及uri模板和uri变量,如上API都是委托给这个API;
MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object… urlVariables)
:提供文件上传方式的请求,得到MockMultipartHttpServletRequestBuilder;
RequestBuilder asyncDispatch(final MvcResult mvcResult)
:创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder;
MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder
API
MockHttpServletRequestBuilder header(String name, Object… values)
/MockHttpServletRequestBuilder headers(HttpHeaders httpHeaders)
:添加头信息;
MockHttpServletRequestBuilder contentType(MediaType mediaType)
:指定请求的contentType头信息;
MockHttpServletRequestBuilder accept(MediaType… mediaTypes
)/MockHttpServletRequestBuilder accept(String… mediaTypes)
:指定请求的Accept头信息;
MockHttpServletRequestBuilder content(byte[] content)
/MockHttpServletRequestBuilder content(String content)
:指定请求Body体内容;
MockHttpServletRequestBuilder cookie(Cookie… cookies)
:指定请求的Cookie;
MockHttpServletRequestBuilder locale(Locale locale)
:指定请求的Locale;
MockHttpServletRequestBuilder characterEncoding(String encoding)
:指定请求字符编码;
MockHttpServletRequestBuilder requestAttr(String name, Object value)
:设置请求属性数据;
MockHttpServletRequestBuilder sessionAttr(String name, Object value)
/MockHttpServletRequestBuilder sessionAttrs(Map<string, object>sessionAttributes)
:设置请求session属性数据;
MockHttpServletRequestBuilder flashAttr(String name, Object value)
/MockHttpServletRequestBuilder flashAttrs(Map<string, object> flashAttributes)
:指定请求的flash信息,比如重定向后的属性信息;
MockHttpServletRequestBuilder session(MockHttpSession session)
:指定请求的Session;
MockHttpServletRequestBuilder principal(Principal principal)
:指定请求的Principal;
MockHttpServletRequestBuilder contextPath(String contextPath)
:指定请求的上下文路径,必须以“/”开头,且不能以“/”结尾;
MockHttpServletRequestBuilder pathInfo(String pathInfo)
:请求的路径信息,必须以“/”开头;
MockHttpServletRequestBuilder secure(boolean secure)
:请求是否使用安全通道;
MockHttpServletRequestBuilder with(RequestPostProcessor postProcessor)
:请求的后处理器,用于自定义一些请求处理的扩展点;
MockMultipartHttpServletRequestBuilder
继承自MockHttpServletRequestBuilder
,又提供了如下API
MockMultipartHttpServletRequestBuilder file(String name, byte[] content)
/MockMultipartHttpServletRequestBuilder file(MockMultipartFile file)
:指定要上传的文件;
ResultActions
调用MockMvc.perform(RequestBuilder requestBuilder)
后将得到ResultActions
,通过ResultActions
完成如下三件事:
ResultActions andExpect(ResultMatcher matcher)
:添加验证断言来判断执行请求后的结果是否是预期的;
ResultActions andDo(ResultHandler handler)
:添加结果处理器,用于对验证成功后执行的动作,如输出下请求/结果信息用于调试;
MvcResult andReturn()
:返回验证成功后的MvcResult
;用于自定义验证/下一步的异步处理;
ResultMatcher/MockMvcResultMatchers
ResultMatcher
用来匹配执行完请求后的结果验证,其就一个match(MvcResult result)
断言方法,如果匹配失败将抛出相应的异常;
spring mvc测试框架提供了很多ResultMatchers
来满足测试需求。注意这些ResultMatchers
并不是ResultMatcher
的子类,而是返回ResultMatcher
实例的。
Spring mvc测试框架为了测试方便提供了MockMvcResultMatchers
静态工厂方法方便操作;
MockMvcResultMatchers
静态工厂方法
HandlerResultMatchers handler()
:请求的Handler验证器,比如验证处理器类型/方法名;此处的Handler其实就是处理请求的控制器;
RequestResultMatchers request()
:得到RequestResultMatchers验证器;
ModelResultMatchers model()
:得到模型验证器;
ViewResultMatchers view()
:得到视图验证器;
FlashAttributeResultMatchers flash()
:得到Flash属性验证;
StatusResultMatchers status()
:得到响应状态验证器;
HeaderResultMatchers header()
:得到响应Header验证器;
CookieResultMatchers cookie()
:得到响应Cookie验证器;
ContentResultMatchers content()
:得到响应内容验证器;
JsonPathResultMatchers jsonPath(String expression, Object … args)
/ResultMatcher jsonPath(String expression, Matcher matcher)
:得到Json表达式验证器;
XpathResultMatchers xpath(String expression, Object... args)
/XpathResultMatchers xpath(String expression, Map<String,String> namespaces, Object... args)
:得到Xpath表达式验证器;
ResultMatcher forwardedUrl(final String expectedUrl)
:验证处理完请求后转发的url(绝对匹配);
ResultMatcher forwardedUrlPattern(final String urlPattern)
:验证处理完请求后转发的url(Ant风格模式匹配,@since spring4);
ResultMatcher redirectedUrl(final String expectedUrl)
:验证处理完请求后重定向的url(绝对匹配);
ResultMatcher redirectedUrlPattern(final String expectedUrl)
:验证处理完请求后重定向的url(Ant风格模式匹配,@since spring4);