SpringBoot 教程 & 笔记 |Demo02- 添加单元测试

本贴最后更新于 2101 天前,其中的信息可能已经沧海桑田

本教程在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);


  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    944 引用 • 1459 回帖 • 17 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...