• SpringBoot使用MockMVC单元测试Controller


    对模块进行集成测试时,希望能够通过输入URL对Controller进行测试,如果通过启动服务器,建立http client进行测试,这样会使得测试变得很麻烦,比如,启动速度慢,测试验证不方便,依赖网络环境等,这样会导致测试无法进行,为了可以对Controller进行测试,可以通过引入MockMVC进行解决。

      MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。

           MockMvcBuilder是用来构造MockMvc的构造器,其主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(此种方式并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。对于我们来说直接使用静态工厂MockMvcBuilders创建即可。

    下面就写一个简单的案例,告诉你是如何使用MockMvc进行Controller测试的

    第一步、创建项目

    创建一个Maven项目(springboot-junit),并配置pom.xml,参照下面代码

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>org.lvgang</groupId>
      <artifactId>springboot-junit</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>jar</packaging>
    
      <name>springboot-junit</name>
      <url>http://maven.apache.org</url>
    
      <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.3.RELEASE</version>
      </parent>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
      </dependencies>
    </project>
    

    创建一个Controller类,我们在后面就测试空上Controller

    package org.lvgang;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    @RestController
    public class HelloController {
    
        @RequestMapping("/")
        public String hello(String name){
            return "hello "+name;
        }
    
    }
    

    第二步、编写测试类

    下面我们就是编写测试类了

    package org.lvgang;
    
    import org.junit.Assert;
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.context.web.WebAppConfiguration;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.MvcResult;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    //SpringBoot1.4版本之前用的是SpringJUnit4ClassRunner.class
    @RunWith(SpringRunner.class)
    //SpringBoot1.4版本之前用的是@SpringApplicationConfiguration(classes = Application.class)
    @SpringBootTest(classes = App.class)
    //测试环境使用,用来表示测试环境使用的ApplicationContext将是WebApplicationContext类型的
    @WebAppConfiguration
    public class HelloControllerTest {
    
        @Autowired
        private WebApplicationContext webApplicationContext;
        private MockMvc mockMvc;
    
        @Before
        public void setUp() throws Exception{
            //MockMvcBuilders.webAppContextSetup(WebApplicationContext context):指定WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的MockMvc;
            mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();//建议使用这种
        }
    
        @Test
        public void getHello() throws Exception{
    
            /**
             * 1、mockMvc.perform执行一个请求。
             * 2、MockMvcRequestBuilders.get("XXX")构造一个请求。
             * 3、ResultActions.param添加请求传值
             * 4、ResultActions.accept(MediaType.TEXT_HTML_VALUE))设置返回类型
             * 5、ResultActions.andExpect添加执行完成后的断言。
             * 6、ResultActions.andDo添加一个结果处理器,表示要对结果做点什么事情
             *   比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。
             * 5、ResultActions.andReturn表示执行完成后返回相应的结果。
             */
    
            MvcResult mvcResult= mockMvc.perform(MockMvcRequestBuilders.get("/")
                    .param("name","lvgang")
                    .accept(MediaType.TEXT_HTML_VALUE))
                   // .andExpect(MockMvcResultMatchers.status().isOk())             //等同于Assert.assertEquals(200,status);
                   // .andExpect(MockMvcResultMatchers.content().string("hello lvgang"))    //等同于 Assert.assertEquals("hello lvgang",content);
                    .andDo(MockMvcResultHandlers.print())
                    .andReturn();
            int status=mvcResult.getResponse().getStatus();                 //得到返回代码
            String content=mvcResult.getResponse().getContentAsString();    //得到返回结果
    
            Assert.assertEquals(200,status);                        //断言,判断返回代码是否正确
            Assert.assertEquals("hello lvgang",content);            //断言,判断返回的值是否正确
        }
    }
    

    整个测试过程如下:

    1、准备测试环境

    2、通过MockMvc执行请求

    3、添加验证断言

    4、添加结果处理器

    5、得到MvcResult进行自定义断言/进行下一步的异步请求

    6、卸载测试环境

    第三步、测试结果

    通过执行HelloControllerTest,得到以下结果:

    并且把整个返回结果都打印到了Console中

    MockHttpServletRequest:
          HTTP Method = GET
          Request URI = /
           Parameters = {name=[lvgang]}
              Headers = {Accept=[text/html]}
    
    Handler:
                 Type = org.lvgang.HelloController
               Method = public java.lang.String org.lvgang.HelloController.hello(java.lang.String)
    
    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=[text/html;charset=UTF-8], Content-Length=[12]}
         Content type = text/html;charset=UTF-8
                 Body = hello lvgang
        Forwarded URL = null
       Redirected URL = null
              Cookies = []

    通过以上代码,我们就完成了一个简单的案例。

    附:

    RequestBuilder/MockMvcRequestBuilders

    在上面的测试类中,我们用到了这么一个类MockMvcRequestBuilders用来构建请求的,此类有以下主要的API:

    MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder;如get(/user/{id}, 1L);
    MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables):同get类似,但是是POST方法;
    MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables):同get类似,但是是PUT方法;
    MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) :同get类似,但是是DELETE方法;
    MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables):同get类似,但是是OPTIONS方法;
    MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables): 提供自己的Http请求方法及uri模板和uri变量,如上API都是委托给这个API;
    MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables):提供文件上传方式的请求,得到MockMultipartHttpServletRequestBuilder;
    RequestBuilder asyncDispatch(final MvcResult mvcResult):创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder;
    
    

    MockMvcRequestBuilders通过方法得到两类Builder,一个是MockHttpServletRequestBuilder ,一个是MockMultipartHttpServletRequestBuilder (上传文件)

    MockHttpServletRequestBuilder:

    MockHttpServletRequestBuilder 主要有一下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 param(String name,String... values):请求传入参数
    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:

    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)断言方法,如果匹配失败将抛出相应的异常;此类案例中并为使用,请自行查看。具体提供以下API:

    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);


    https://my.oschina.net/sdlvzg/blog/1594821
  • 相关阅读:
    Spring Boot 中使用 @Transactional 注解配置事务管理
    springboot 整合Swagger2的使用
    Vue的参数请求与传递
    SpringMVC的全局异常处理
    SpringBoot集成MyBatis的Bean配置方式
    Springboot整合通用mapper
    个人作业——软件工程实践总结作业
    团队作业第二次—项目选题报告(追光的人)
    结对第二次—文献摘要热词统计及进阶需求
    结对第一次—原型设计(文献摘要热词统计)
  • 原文地址:https://www.cnblogs.com/q1359720840/p/13781740.html
Copyright © 2020-2023  润新知