zoukankan      html  css  js  c++  java
  • 使用MockMvc测试Restful接口

    1. MockMvc

    MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。

    接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilderDefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。MockMvcBuilders提供了对应的创建方法standaloneSetup方法和webAppContextSetup方法,在使用时直接调用即可。

    2. 引入jar包

    创建SpringBoot项目中默认引入的spring-boot-starter-test间接引入了spring-test,因此无需再额外引入jar包。最终的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.2.6.RELEASE</version>
            <relativePath/> <!-- lookup parent from repository -->
        </parent>
        <groupId>com.example</groupId>
        <artifactId>mockdemo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <name>mockdemo</name>
        <description>Demo project for Spring Boot</description>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>1.18.12</version>
                <scope>provided</scope>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-jdbc</artifactId>
            </dependency>
    
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
    
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-io</artifactId>
                <version>1.3.2</version>
            </dependency>
    
            <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>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <scope>test</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                </plugin>
            </plugins>
        </build>
    
    </project>
    
    

    3. 创建业务bean和控制器

    User Bean

    package com.example.mockdemo.domain;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    import javax.validation.constraints.Past;
    import java.util.Date;
    
    /**
     * @author john
     * @date 2020/4/9 - 18:01
     */
    @Slf4j
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private int id;
        private String username;
        private String password;
        @Past(message = "生日必须是过去的时间")
        private Date birthday;
    }
    
    

    FileInfo Dto

    package com.example.mockdemo.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    /**
     * @author john
     * @date 2020/4/10 - 10:00
     */
    @Slf4j
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class FileInfo {
        private String path;
    }
    
    

    UserQueryCondition Dto

    package com.example.mockdemo.dto;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.extern.slf4j.Slf4j;
    
    @Slf4j
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class UserQueryCondition {
        private String username;
        private int age;
        private int ageTo;
        private String xxx;
    }
    
    

    FileController

    package com.example.mockdemo.controller;
    
    import com.example.mockdemo.dto.FileInfo;
    import org.apache.commons.io.IOUtils;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.multipart.MultipartFile;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.InputStream;
    import java.io.OutputStream;
    
    /**
     * @author john
     * @date 2020/4/10 - 9:54
     */
    @RestController
    @RequestMapping("/file")
    public class FileController {
    
        private String folder = "D:\test";
    
        @PostMapping
        //文件上传
        public FileInfo upload(MultipartFile file) throws Exception {
    
            System.out.println(file.getName());
            System.out.println(file.getOriginalFilename());
            System.out.println(file.getSize());
    
            File localFile = new File(folder, "aa.txt");
    
            file.transferTo(localFile);
    
            return new FileInfo(localFile.getAbsolutePath());
        }
    
        @GetMapping("/{id}")
        //文件下载
        public void download(@PathVariable String id, HttpServletRequest request, HttpServletResponse response) throws Exception {
    
            try (InputStream inputStream = new FileInputStream(new File(folder, id + ".txt"));
                 OutputStream outputStream = response.getOutputStream();) {
    
                response.setContentType("application/x-download");
                response.addHeader("Content-Disposition", "attachment;filename=test.txt");
    
                IOUtils.copy(inputStream, outputStream);
                outputStream.flush();
            }
    
        }
    
    }
    
    

    UserController

    package com.example.mockdemo.controller;
    
    import com.example.mockdemo.domain.User;
    import com.example.mockdemo.dto.UserQueryCondition;
    import org.springframework.data.domain.Pageable;
    import org.springframework.data.web.PageableDefault;
    import org.springframework.web.bind.annotation.*;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @author john
     * @date 2020/4/9 - 18:00
     */
    @RestController
    @RequestMapping("/user")
    public class UserController {
        @PostMapping
        //创建用户
        public User create(@RequestBody User user) {
            user.setId(1);
            return user;
        }
    
        @PutMapping("/{id:\d+}")
        //更新用户
        public User update(@RequestBody User user) {
            user.setId(1);
            return user;
        }
    
        @DeleteMapping("/{id:\d+}")
        //删除用户
        public void delete(@PathVariable String id) {
            System.out.println("用户id为" + id + "删除成功");
        }
    
        @GetMapping
        //查询用户
        public List<User> query(UserQueryCondition condition, @PageableDefault(page = 2, size = 17, sort = "username,asc") Pageable pageable) {
            System.out.println(pageable.getPageSize());
            System.out.println(pageable.getPageNumber());
            System.out.println(pageable.getSort());
            List<User> users = new ArrayList<>();
            users.add(new User(1, "john", "", new Date()));
            users.add(new User(2, "tom", "", new Date()));
            users.add(new User(3, "jim", "", new Date()));
            return users;
        }
    
        @GetMapping("/{id:\d+}")
        //获取具体用户信息
        public User getInfo(@PathVariable String id) {
            System.out.println("进入getInfo服务");
            User user = new User();
            user.setUsername("tom");
            return user;
        }
    }
    
    

    4. 编写测试类

    package com.example.mockdemo;
    
    import java.time.LocalDateTime;
    import java.time.ZoneId;
    import java.util.Date;
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.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.mock.web.MockMultipartFile;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    class MockdemoApplicationTests {
    
        private MockMvc mockMvc;
    
        @Autowired
        private WebApplicationContext wac;
    
        @BeforeEach
        public void setup() {
            mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
    
        @Test
        //测试删除用户接口
        public void whenDeleteSuccess() throws Exception {
            mockMvc.perform(delete("/user/1")
                    .contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(status().isOk());
        }
    
        @Test
        //测试更新用户数据
        public void whenUpdateSuccess() throws Exception {
    
            Date date = new Date(LocalDateTime.now().plusYears(1).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
            System.out.println(date.getTime());
            String content = "{"id":"1", "username":"tom","password":null,"birthday":" + date.getTime() + "}";
            String reuslt = mockMvc.perform(put("/user/1").contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(content))
                    .andExpect(status().isOk())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(jsonPath("$.id").value("1"))
                    .andReturn().getResponse().getContentAsString();
    
            System.out.println(reuslt);
        }
    
        @Test
        //测试创建用户成功
        public void whenCreateSuccess() throws Exception {
    
            Date date = new Date();
            System.out.println(date.getTime());
            String content = "{"username":"tom","password":null,"birthday":" + date.getTime() + "}";
            String reuslt = mockMvc.perform(post("/user").contentType(MediaType.APPLICATION_JSON_VALUE)
                    .content(content))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.id").value("1"))
                    .andReturn().getResponse().getContentAsString();
    
            System.out.println(reuslt);
        }
    
        @Test
        //测试获取用户信息失败
        public void whenGetInfoFail() throws Exception {
            mockMvc.perform(get("/user/a")
                    .contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(status().is4xxClientError());
        }
    
        @Test
        //测试获取用户信息成功
        public void whenGetInfoSuccess() throws Exception {
            String result = mockMvc.perform(get("/user/1")
                    .contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(status().isOk())
                    .andExpect(jsonPath("$.username").value("tom"))
                    .andReturn().getResponse().getContentAsString();
    
            System.out.println(result);
        }
    
        @Test
        //测试查询用户数据接口
        public void whenQuerySuccess() throws Exception {
            String result = mockMvc.perform(
                    get("/user").param("username", "jojo")
                            .param("age", "18")
                            .param("ageTo", "60")
                            .param("xxx", "yyy")
                            .param("size", "15")
                            .param("page", "3")
                            .param("sort", "age,desc")
                            .contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(status().isOk()).
                            andExpect(jsonPath("$.length()").value(3))
                    .andReturn().getResponse().getContentAsString();
    
            System.out.println(result);
        }
    
        @Test
        //测试文件上传
        public void whenUploadSuccess() throws Exception {
            MockMultipartFile file = new MockMultipartFile("file", "test.txt", "multipart/form-data", "hello upload".getBytes("UTF-8"));
            String result = mockMvc.perform(multipart("/file").file(file))
                    .andExpect(status().isOk())
                    .andReturn().getResponse().getContentAsString();
            System.out.println(result);
        }
    
    }
    
    

    5. 代码分享

    微云下载

    6. 参考

    Server-Side Tests

    Spring MVC测试框架详解——服务端测试

    官方示例

    Java后端安全开发Spring Security开发REST服务

  • 相关阅读:
    算法设计与分析——背包问题求解
    并行多核体系结构基础——第五章的多级高速缓存中的包含、排他、NINIE策略
    并行多核体系结构基础——第五章知识点和课后习题
    多耦合效应下的网络传播演化与分析
    算法设计与分析——矩阵链相乘求解
    算法设计与分析——动态规划之矩阵连乘
    并行多核体系结构基础——第五章的伪LRU(PLRU)算法简要介绍
    算法设计与分析——分治DC算法
    常见概率分布的特征函数推导
    算法设计与分析——最长公共子序列问题
  • 原文地址:https://www.cnblogs.com/ifme/p/12671773.html
Copyright © 2011-2022 走看看