其他分享
首页 > 其他分享> > mockMvc测试

mockMvc测试

作者:互联网

1.环境准备

本文主要是介绍mock测试方面的知识,用到的环境是 idea + jdk8 + mysql5.5.49 + Junit5 + springBoot 2.6 + mokito

1.1数据库脚本准备

-- 创建订单表
CREATE TABLE `sale_order` (
  `id` bigint NOT null AUTO_INCREMENT COMMENT '客户订单ID',
  `sale_order_code` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '订单编号',
  `customer` varchar(32) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '客户',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uni_sale_order_code` (`sale_order_code`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='客户订单(销售订单)';

-- 创建订单颜色明细表
CREATE TABLE `sale_order_detail` (
  `id` bigint NOT NULL AUTO_INCREMENT COMMENT '客户订单明细ID',
  `sale_order_id` bigint NOT NULL COMMENT '客户订单ID',
  `color` varchar(50) COLLATE utf8mb4_general_ci DEFAULT NULL,
  `quantity` bigint DEFAULT NULL COMMENT '数量',
   `receiver_price` decimal(22,2) DEFAULT NULL COMMENT '接单价格',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci ROW_FORMAT=DYNAMIC COMMENT='客户订单明细表(下单信息)';

1.2.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.2</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.fufulong.demo</groupId>
    <artifactId>mock-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mock-demo</name>
    <description>mock-demo</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.6.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mockito/mockito-core -->
        <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>3.12.4</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.5.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.75</version>
        </dependency>
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.2</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
        <resources>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.properties</include>
                    <include>**/*.xml</include>
                    <include>**/*.yml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>META-INF/**</include>
                    <include>template/*</include>
                </includes>
                <filtering>false</filtering>
            </resource>
        </resources>
    </build>

</project>

1.3 配置文件准备

spring:
  application:
    name: mock-demo
  datasource:
    username: root
    password: xxxx
    url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&rewriteBatchedStatements=true
  servlet:
    multipart:
      max-request-size: 100MB
      max-file-size: 10MB

server:
  port: 9000
  servlet:
    context-path: /mock-demo

2. mockMvc 的使用方法

2.1 初始化mockMvc

使用@SpringBootTest注解会加载整个Context。这样我们可以自动获得所有在Context中注入的Bean,以及从application.properties中加载的配置信息。

@SpringBootTest中声明webEnvironment为WebEnvironment.MOCK(默认值就是WebEnvironment.MOCK)后,结合@AutoConfigureMockMvc注解,在测试的时候会得到一个模拟的Web/Servlet环境。

因为没有Web Server,所以就无法使用RestTemplate,也就只能继续使用MockMVC了。这次MockMVC的实例是由@AutoConfigureMockMvc注解来完成的。这归功于SpringBoot的自动化配置。

junit5和junit4环境,初始化mocKMvc的方法不一样,如果是Junit5,初始化 mockMvc的代码如下:

@SpringBootTest(classes = MockDemoApplication.class)
@AutoConfigureMockMvc
class MockDemoApplicationTests {
    @Autowired
    private MockMvc mockMvc;

}


也可以使用另外一种方式,使用MockMvcBuilders 得静态方法初始化mockMvc,这样做还可以设置每次mock测试都要执行的动作,期望等

image-20220114151808824

@SpringBootTest(classes = MockDemoApplication.class)
class MockDemoApplicationTests {
    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext webApplicationContext;

    @BeforeEach
    public void setUp(){
        // 设定mockMvc能mock的controller是整个springBoot项目环境中的controller
        mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext). build();
    }
    
    }

2.2 测试post类型的接口

接口方法

@RestController
@RequestMapping("saleOrder")
public class SaleOrderController {

    @Autowired
    private SaleOrderService saleOrderService;

    @PostMapping(value = "/save")
    public DataResponse<Long> save(@RequestBody SaveSaleOrderReq req){
        Long id = saleOrderService.save(req);
        return DataResponse.ok(id);
    }

}

测试方法

@Test
public void test1() throws Exception {
    SaleOrder saveOrder = new SaleOrder();
    saveOrder.setSaleOrderCode("0001");
    saveOrder.setCustomer("小明");

    MockHttpServletRequestBuilder requestBuilder =
        //请求路径,不需要带前面 servletContext部分
        MockMvcRequestBuilders.post("/saleOrder/save")
        // post请求返回的mediaType
        .accept(MediaType.APPLICATION_JSON)
        // post请求的请求内容的 mediaType
        .contentType(MediaType.APPLICATION_JSON)
        // post 请求参数内容
        .content(JSON.toJSONString(saveOrder));
    MvcResult mvcResult = mockMvc.perform(requestBuilder)
        // 设置期望的结果,用 ResultMatcher 来表示
        .andExpect(MockMvcResultMatchers.status().isOk())
        // 内置的打印mock请求结果
        .andDo(MockMvcResultHandlers.print())
        // 正式执行接口,并返回接口的返回值
        .andReturn();
    // 把 mvcResult 的 response对象,转换成 json,然后打印显示
    String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
    System.out.println(s);
}

结果如下所示:

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /saleOrder/save
       Parameters = {}
          Headers = [Content-Type:"application/json", Accept:"application/json", Content-Length:"44"]
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.fufulong.demo.mockdemo.controller.SaleOrderController
           Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#save(SaveSaleOrderReq)

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"]
     Content type = application/json
             Body = {"successful":true,"code":"200","message":null,"data":1}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
{"successful":true,"code":"200","message":null,"data":1}


2.3 测试get类型的接口 (requestParam参数类型)

接口方法

@GetMapping(value = "/get-one")
public DataResponse<SaleOrder> getOne(@RequestParam(value = "saleOrderId") Long saleOrderId){
    SaleOrder saleOrder = saleOrderService.selectOne(saleOrderId);
    return DataResponse.ok(saleOrder);
}

测试方法

@Test
public void test2() throws Exception {
    MockHttpServletRequestBuilder requestBuilder =
        //请求路径,不需要带前面 servletContext部分
        MockMvcRequestBuilders.get("/saleOrder/get-one")
        // 设置请求参数
        .param("saleOrderId","1");
    MvcResult mvcResult = mockMvc.perform(requestBuilder)
        // 设置期望的结果,用 ResultMatcher 来表示
        .andExpect(MockMvcResultMatchers.status().isOk())
        .andDo(MockMvcResultHandlers.print())
        .andReturn();
    String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
    System.out.println(s);

}

测试结果输出

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /saleOrder/get-one
       Parameters = {saleOrderId=[1]}
          Headers = []
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.fufulong.demo.mockdemo.controller.SaleOrderController
           Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#getOne(Long)

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"]
     Content type = application/json
             Body = {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
{"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}


2.4 测试get类型的接口 (path参数类型)

接口代码

@GetMapping(value = "/get-one/{saleOrderCode}/{id}")
public DataResponse<SaleOrder> getOneByCode(@PathVariable(value = "saleOrderCode") String saleOrderCode,
                                            @PathVariable(value = "id") Long id ){
    SaleOrder saleOrder = saleOrderService.getOneByCode(saleOrderCode,id);
    return DataResponse.ok(saleOrder);
}

测试方法

@Test
public void test3() throws Exception {
    String saleOrderCode = "0001";
    Long id = 1L;
    MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.get("/saleOrder/get-one/{saleOrderCode}/{id}",saleOrderCode,id);
    MvcResult mvcResult = mockMvc.perform(requestBuilder)
        // 设置期望的结果,用 ResultMatcher 来表示
        .andExpect(MockMvcResultMatchers.status().isOk())
        .andDo(MockMvcResultHandlers.print())
        .andReturn();
    String s = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
    System.out.println(s);
}

测试结果打印

MockHttpServletRequest:
      HTTP Method = GET
      Request URI = /saleOrder/get-one/0001/1
       Parameters = {}
          Headers = []
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.fufulong.demo.mockdemo.controller.SaleOrderController
           Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#getOneByCode(String, Long)

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"]
     Content type = application/json
             Body = {"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []
{"successful":true,"code":"200","message":null,"data":{"id":1,"saleOrderCode":"0001","customer":"小明"}}

2.5 测试上传文件

接口代码

@RequestMapping(value = "/uploadFile")
    public DataResponse<Void> uploadFile(@RequestParam(value = "file") MultipartFile file) throws IOException {
        InputStream inputStream = null;
        OutputStream outputStream = null;
        try{
            inputStream = file.getInputStream();
            outputStream = FileUtil.getOutputStream(new File(Objects.requireNonNull(file.getOriginalFilename())));
            IoUtil.copy(inputStream,outputStream);
        }finally {
            if (inputStream != null){
                inputStream.close();
            }
            if (outputStream != null){
                outputStream.close();
            }
        }

        return DataResponse.ok();
    }

测试代码

   @Test
    public void test4() throws Exception {
        File file = new File("C:\\Users\\付福龙\\Desktop\\兔子.jpeg");
        MockMultipartFile uploadFile = new MockMultipartFile("file", "兔子.jpeg", MediaType.IMAGE_JPEG_VALUE, new FileInputStream(file));
        MockHttpServletRequestBuilder requestBuilder = MockMvcRequestBuilders.multipart("/saleOrder/uploadFile").file(uploadFile).contentType( MediaType.IMAGE_JPEG);
        MvcResult mvcResult = mockMvc.perform(requestBuilder)
                // 设置期望的结果,用 ResultMatcher 来表示
                .andExpect(MockMvcResultMatchers.status().isOk())
                .andDo(MockMvcResultHandlers.print())
                .andReturn();
    }

测试结果

MockHttpServletRequest:
      HTTP Method = POST
      Request URI = /saleOrder/uploadFile
       Parameters = {}
          Headers = [Content-Type:"image/jpeg"]
             Body = <no character encoding set>
    Session Attrs = {}

Handler:
             Type = com.fufulong.demo.mockdemo.controller.SaleOrderController
           Method = com.fufulong.demo.mockdemo.controller.SaleOrderController#uploadFile(MultipartFile)

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"]
     Content type = application/json
             Body = {"successful":true,"code":"200","message":null,"data":null}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []


image-20220118151329116

3.mockMvc测试controller总结

  1. 先有业务接口方法
  2. 新建的测试类中,需要先初始化mockMvc对象
  3. 根据接口方法的类型不同(post/get/multipart等),选择构建不同的MockHttpServletRequestBuilder 对象, 在这里设置请求地址,注意地址是不需要 地址端口和servletContextpath前缀的,且需要注意用"/"开头. 然后设置 queryParam或者pathParam或者 content,还可以设置请求头等
  4. 调用mockMvc的方法,指定需要执行的请求, mockMvc.perform(MockHttpServletRequestBuilder )
  5. 然后设置断言,断言可以设置多个,使用方法 andExpect(ResultMatcher matcher) 设置, MockMvcResultMatchers中有许多常用的断言结果匹配器,可以使用
  6. 然后设置结果处理方法, 使用方法 ResultActions andDo(ResultHandler handler) 来处理,同样 MockMvcResultHandlers 总有需要封装好的静态方法可以用
  7. 然后 调用方法 MvcResult andReturn() ,此时才会真的执行接口, 得到 MvcResult 结果
  8. 可以使用 mvcResult.getResponse() 得到 MockHttpServletResponse 对象, 这个对象有许多请求结果的信息,比如状态,内容等, 可以根据这些内容写后续的验证代码

4. mockMvc测试重要API

41. MockMvcRequestBuilders

4.2 MockMvcRequestBuilder

4.3 ResultActions

4.4 MockMvcResultMatchers

4.5 MockMvcResultHandlers

这里的方法主要是打印或者日志记录mock测试的主要信息,注意如果是打印到系统的控制台,使用的是系统的编码方式,如果是wIndows系统,就是ISO-8859-1,那么输出的中文就是乱码了.
image-20220118170300113

4.6 MockHttpServletResponse

标签:String,接口,测试,mockMvc,null,id,请求
来源: https://blog.csdn.net/weixin_43422437/article/details/122611803