spring中MockMvc编写自动化单元测试用例

使用spring的MockMvc编写自动化测试用例,提高接口测试通过率,提高自身代码质量,减少常见BUG出现。
废话不多说直接上代码。
maven依赖:

<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>com.demo</groupId>
	<artifactId>com.demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-test-demo-1</name>


	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.4.RELEASE</version>
		<relativePath />
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.0.6</version>
			<exclusions>
				<exclusion>
					<artifactId>jsqlparser</artifactId>
					<groupId>com.github.jsqlparser</groupId>
				</exclusion>
				<exclusion>
					<artifactId>mybatis-spring</artifactId>
					<groupId>org.mybatis</groupId>
				</exclusion>
				<exclusion>
					<artifactId>mybatis</artifactId>
					<groupId>org.mybatis</groupId>
				</exclusion>
			</exclusions>
		</dependency>
		<!-- Mysql Driver -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.16</version>
		</dependency>
		<!-- /Mysql Driver -->
		<dependency>
			<groupId>org.freemarker</groupId>
			<artifactId>freemarker</artifactId>
		</dependency>
		<dependency>
			<groupId>com.alibaba</groupId>
			<artifactId>fastjson</artifactId>
			<version>1.2.44</version>
		</dependency>

	</dependencies>
</project>

实体类代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.demo.entity;

import java.io.Serializable;


public class ResultResponse<T> implements Serializable {

    public static final Integer SUCCESS_CODE = 0;
    private static final long serialVersionUID = -6557898536448299915L;
    private Integer code;
    private String message;
    private T data;

    public ResultResponse() {
    }

	public Integer getCode() {
		return code;
	}

	public void setCode(Integer code) {
		this.code = code;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public T getData() {
		return data;
	}

	public void setData(T data) {
		this.data = data;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((code == null) ? 0 : code.hashCode());
		result = prime * result + ((data == null) ? 0 : data.hashCode());
		result = prime * result + ((message == null) ? 0 : message.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ResultResponse other = (ResultResponse) obj;
		if (code == null) {
			if (other.code != null)
				return false;
		} else if (!code.equals(other.code))
			return false;
		if (data == null) {
			if (other.data != null)
				return false;
		} else if (!data.equals(other.data))
			return false;
		if (message == null) {
			if (other.message != null)
				return false;
		} else if (!message.equals(other.message))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "ResultResponse [code=" + code + ", message=" + message + ", data=" + data + "]";
	}


}

user实体类:

package com.demo.entity;

import java.io.Serializable;

public class UserDemo implements Serializable {

	private static final long serialVersionUID = -1L;
	private Integer id;
	
	private String userName;

	public Integer getId() {
		return id;
	}

	public void setId(Integer id) {
		this.id = id;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result + ((userName == null) ? 0 : userName.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		UserDemo other = (UserDemo) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (userName == null) {
			if (other.userName != null)
				return false;
		} else if (!userName.equals(other.userName))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "UserDemo [id=" + id + ", userName=" + userName + "]";
	}
	
	
}

controller的代码:

package com.demo.controller;


import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
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.RestController;

import com.demo.entity.ResultResponse;
import com.demo.entity.UserDemo;

@RestController
@RequestMapping("/demo")
public class DemoController {

	
	@GetMapping("/getOne/{id}")
	public ResultResponse<UserDemo> getOne(@PathVariable Integer id) {
		UserDemo userDemo = new UserDemo(); 
		userDemo.setId(id);
		userDemo.setUserName("测试");
		ResultResponse<UserDemo>  resultResponse = new ResultResponse<UserDemo>();
		resultResponse.setCode(200);
		resultResponse.setMessage("success");
		resultResponse.setData(userDemo);
		return resultResponse;
	}
	
	@PostMapping(value = "/editOne",consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
	public ResultResponse<Boolean> editOne(@RequestBody UserDemo userDemo) {
		System.out.println("要编辑客户:"+userDemo);
		ResultResponse<Boolean>  resultResponse = new ResultResponse<Boolean>();
		resultResponse.setCode(200);
		resultResponse.setMessage("success");
		resultResponse.setData(null);
		return resultResponse;
	}
}

test下的测试用例代码:

package com.demo.controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.demo.SpringTestDemoApplication;
import com.demo.entity.ResultResponse;
import com.demo.entity.UserDemo;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;

import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.core.IsNull.nullValue;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

/**
 * @author DaXiong
 * @create 2020-02-21 9:09
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {SpringTestDemoApplication.class})
public class DemoControllerTest {

    @Resource
    private WebApplicationContext webAC;

    private MockMvc mockMvc;

    private static final String URI = "/demo";


    @Before
    public void setUp(){
        mockMvc = MockMvcBuilders.webAppContextSetup(webAC).build();
    }

    @Test
    // 执行测试要执行的数据库脚本(脚本位置: src/test/resources/sql/DemoControllerTest/testGetOne.sql)
    @Sql(scripts = {"classpath:sql/DemoControllerTest/testGetOne.sql"})
    // 事务回滚,方法执行完后,把刚开始执行脚本的数据恢复
    @Rollback(true)
    // 开始事务才会回滚,不然每次执行数据库脚本插入重复数据
    @Transactional 
    public void testGetOne() throws Exception {
    	int id = 1;
        MvcResult mvcResult = mockMvc.perform(get(URI + "/getOne/{id}",id)
        		.contentType(MediaType.APPLICATION_JSON_UTF8)
                .header("key1", "消息头的值")) // 如果请求要有特定的消息头可以在此添加
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
                .andExpect(jsonPath("$.code", is(200)))
                .andExpect(jsonPath("$.message", containsString("success")))
                .andExpect(jsonPath("$.data.userName", is("测试")))
                .andDo(print())
                .andReturn();
        
        String contentAsString = mvcResult.getResponse().getContentAsString();
        ResultResponse response = JSONObject.parseObject(contentAsString, ResultResponse.class);
        UserDemo userDemo = JSONObject.parseObject(JSON.toJSONString(response.getData()),UserDemo.class);
        
        //如果不能通过接口返回值判断是否成功,例如新增接口
        // 可以在这里通过调用查询接口,查询是否查到自己调用接口后新增的客户,通过一下比较是否与自己
        // 新增的一致,一致则接口成功
        // 值为空则报错,用于检验不能为null的情况
        assertNotNull(userDemo);
        assertEquals(Integer.valueOf(id),userDemo.getId());
        
        
    }
    
  @Test
  // 如果该测试用例不需要执行脚本,则将该注解注释即可
//  @Sql(scripts = {"classpath:sql/DemoControllerTest/testEditOne.sql"})
  @Rollback(true)
  @Transactional
  public void testEditOne() throws Exception {
 
	UserDemo userDemo = new UserDemo(); 
	userDemo.setId(2);
	userDemo.setUserName("编辑测试");

      MvcResult mvcResult = mockMvc.perform(post(URI + "/editOne").contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
              .content(JSON.toJSONString(userDemo)))
              .andExpect(status().isOk())
              .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
              .andExpect(jsonPath("$.code", is(200)))
              .andExpect(jsonPath("$.message", containsString("success")))
              .andExpect(jsonPath("$.data", nullValue()))
              .andDo(print())
              .andReturn();


  }

}

执行后的效果图:
spring中MockMvc编写自动化单元测试用例
写完接口后,写测试用例是一个好习惯!

上一篇:MockMvc使用示例类


下一篇:springboot Mock测试模块