前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用MockMVC进行Controller单元测试

使用MockMVC进行Controller单元测试

作者头像
Antony
发布2020-12-03 15:00:24
5.1K0
发布2020-12-03 15:00:24
举报

引入

由于MockMVC是Spring框架自带的测试组件,因此只要在项目中引入spring-boot-starter-test这个测试套件就可以使用Spring-test库中的MockMVC了。 例如Maven项目的pom.xml中添加如下的依赖

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
        </exclusion>
    </exclusions>
</dependency>

以下将介绍如何使用MockMVC+Mockito+JUnit5+JsonUnit进行测试

待测Controller接口

代码语言:javascript
复制
package com.testlink4j.controller;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.testlink4j.domain.Keywords;
import com.testlink4j.service.KeywordsService;

/**
 * Keywords RestController
 *
 * @author Antony
 * 
 */
@RestController
public class KeywordsRestController {

    @Autowired
    private KeywordsService keywordsService;
    @RequestMapping(value = "/api/keywords", method = RequestMethod.GET)
    public Keywords findKeywordById(@RequestParam(value = "id", required = true) Integer id) {
        return keywordsService.findKeywordById(id);
    }
    @PostMapping(value = "/api/keywords")
    public Integer createKeywords(@RequestBody Keywords keywords) {
        return keywordsService.createKeywords(keywords);
    }
    
}

KeywordsRestController 包含了两个Keywords相关的接口,提供查询和创建的功能。 接下来,将以查询接口为例,介绍如何对该接口进行单元测试。

代码语言:javascript
复制
package com.testlink4j.controller;

import com.testlink4j.service.KeywordsService;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.alibaba.fastjson.JSON;
import com.testlink4j.domain.Keywords;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.io.UnsupportedEncodingException;


public class KeywordsControllerTest {

     protected MockMvc mockMvc;

        @Mock
        private KeywordsService keywordsServic;

        @InjectMocks
        KeywordsRestController keywordsRestController;
        @BeforeEach()
        public void setup() {
            MockitoAnnotations.initMocks(this);
            mockMvc = MockMvcBuilders.standaloneSetup(keywordsRestController).build();  //初始化MockMvc对象

        }

  @Test
  public void CreateKeywordsSuccessfullyTest() throws UnsupportedEncodingException, Exception {
      Keywords keywords=Keywords.builder().id(666).keyword("tester").testproject_id(333).notes("tester").build();
      Mockito.when(keywordsServic.findKeywordById(1)).thenReturn(keywords);
            String responseString = mockMvc.perform(
                    get("/api/keywords?id=1")    //请求的url,请求的方法是Post
                            .contentType(MediaType.APPLICATION_JSON)  //数据的格式
            ).andExpect(status().isOk())    //返回的状态是200
                    .andDo(print())         //打印出请求和相应的内容
                    .andReturn().getResponse().getContentAsString();   //将相应的数据转换为字符串
            assertThatJson(responseString).isEqualTo(keywords);
  }
}

findKeywordById接口通过调用KeywordsService来实现具体的查询功能。首先,和普通的基于Mockito单元测试一样,通过@Mock注解来对这个Service进行mock,并通过@InjectMocks注解实现注入。

接下来,通过

代码语言:javascript
复制
mockMvc = MockMvcBuilders.standaloneSetup(keywordsRestController).build()

将keywordsRestController加载进Spring容器。 在测试执行阶段,通过对URI的访问,查询id=1的keyword。 从测试结果来看,发生了如下的一系列过程 1)Spring容器收到访问请求,并由DispatcherServlet 根据@RequestMapping将请求转发给对应的controller的接口。 2)接口收到请求,通过解析@RequestParam获取入参,并调用对应的方法执行(调用service的测试桩来返回mock结果) 3)返回接口调用结果,即HttpServletResponse 4)对response的状态进行断言(200),并打印请求和响应 5)对响应结果进行断言(json)

来看一下用例执行过程中,通过print()方法打印的请求和响应

代码语言:javascript
复制
MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /api/keywords
       Parameters = {id=[1]}
          Headers = [Content-Type:"application/json"]
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.testlink4j.controller.KeywordsRestController
           Method = com.testlink4j.controller.KeywordsRestController#findKeywordById(Integer)
//中间部分省略
MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Content-Type:"application/json"]
     Content type = application/json
             Body = {"id":666,"keyword":"tester","testproject_id":333,"notes":"tester"}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

另外,看一下整个容器的启动耗时

19:29:57.689 [main] INFO org.springframework.test.web.servlet.TestDispatcherServlet - Completed initialization in 6 ms

可以看到,由于整个测试过程中只将被测的controller注入到了Spring容器中,容器的启动过程是非常快速的。

与直接通过类和方法调用的单元测试方式相比,通过使用MockMvc,有如下的不同 1)通过URI进行接口调用,也就是额外测试了DispatcherServlet 和@RequestMapping

2) 对@RequestParam进行了测试(感兴趣的读者可以尝试调用接口时不提供id=1的入参)

3)对接口返回进行了断言

4)对接口返回对象的反序列化进行了断言

下一篇将介绍如何使用MockMvc进行集成测试,并分析MockMVC的具体组成和使用方式。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-11-01,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 软件测试那些事 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 引入
  • 以下将介绍如何使用MockMVC+Mockito+JUnit5+JsonUnit进行测试
    • 待测Controller接口
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档