对模块进行集成测试时,希望能够通过输入URL对Controller进行测试,如果通过启动服务器,建立http client进行测试,这样会使得测试变得很麻烦,比如,启动速度慢,测试验证不方便,依赖网络环境等
MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境,而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便
这里是完整的测试案例:包含Junit5以及Mockmvc
package com.uncle.junittest.bean;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author
* @date 2022-01-27 上午10:30
**/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
/**
* 序列号
*/
private static final long serialVersionUID = -4449140937612137858L;
/**
* 用户id
*/
private String id;
/**
* 昵称
*/
private String fullName;
/**
* 用户名
*/
private String userName;
/**
* 密码
*/
private String password;
/**
* 年龄
*/
private Integer age;
/**
* 性别
*/
private String sex;
}
package com.uncle.junittest.mapper;
import com.uncle.junittest.bean.User;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
/**
* @author
* @date 2022-01-27 下午3:30
**/
@Repository
public interface UserMapper {
/**
* 增加用户的方法
*
* @param user 用户信息
* @return 增加成功返回:1;否则返回:0
*/
@Insert("insert into user values (#{id},#{fullName},#{userName},#{password},#{age},#{sex})")
int saveUser(User user);
/**
* 根据id查询用户信息
*
* @param id 用户id
* @return 用户信息
*/
@Select("select * from user where id = #{id}")
User getUser(String id);
}
package com.uncle.junittest.service;
import com.uncle.junittest.bean.User;
import org.apache.ibatis.annotations.Select;
/**
* @author
* @date 2022-01-27 下午3:29
**/
public interface UserService {
/**
* 增加用户的方法
* @param user 用户信息
* @return 增加成功返回:1;否则返回:0
*/
int saveUser(User user);
/**
* 根据id查询用户信息
* @param id 用户id
* @return 用户信息
*/
User getUser(String id);
}
package com.uncle.junittest.service.impl;
import com.uncle.junittest.bean.User;
import com.uncle.junittest.mapper.UserMapper;
import com.uncle.junittest.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author
* @date 2022-01-27 下午3:29
**/
@Service
public class UserServiceImpl implements UserService {
/**
* UserMapper对象
*/
@Autowired
private UserMapper userMapper;
/**
* 增加用户的方法
* @param user 用户信息
* @return 增加成功返回:1;否则返回:0
*/
@Override
public int saveUser(User user) { return userMapper.saveUser(user); }
/**
* 根据id查询用户信息
* @param id 用户id
* @return 用户信息
*/
@Override
public User getUser(String id) {
return userMapper.getUser(id);
}
}
package com.uncle.junittest.controller;
import com.uncle.junittest.bean.User;
import com.uncle.junittest.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @author
* @date 2022-01-27 下午3:29
**/
@RequestMapping("/test")
@RestController
public class UserController {
/**
* UserService对象
*/
@Autowired
private UserService userService;
/**
* 新增用户
* @param user User
* @return String
*/
@PostMapping("/saveUser")
public String saveUser(@RequestBody User user) {
int i = userService.saveUser(user);
return i == 1 ? user.toString() : "新增用户失败";
}
/**
* 获取用户信息
*
* @return String
*/
@GetMapping("/getUser/{id}")
public String getUser(@PathVariable(value = "id") String id) {
User user = userService.getUser(id);
return user.toString();
}
}
package com.uncle.junittest;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("com.uncle.junittest.mapper")
public class JunitTestApplication {
public static void main(String[] args) {
SpringApplication.run(JunitTestApplication.class, args);
}
}
spring:
datasource:
username: root
password:
url: jdbc:mysql://@rm-2ze44u6e2z7t924t0xo.mysql.rds.aliyuncs.com:3306/
server:
port: 80
mybatis:
configuration:
map-underscore-to-camel-case: true
package com.uncle.junittest.controller;
import com.alibaba.fastjson.JSON;
import com.uncle.junittest.bean.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpHeaders;
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.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
/**
* 用户测试类
*
* @AutoConfigureMockMvc:该注解将会自动配置mockMvc的单元测试
*/
@DisplayName(value = "用户测试类")
@Slf4j
@AutoConfigureMockMvc
@SpringBootTest
class UserControllerTest {
/**
* 每个单元测试之前都要执行
*/
@BeforeEach
void testBeforeEach() {
log.info("测试要开始了!");
}
/**
* 每个单元测试之后都要执行
*/
@AfterEach
void testAfterEach() {
log.info("测试结束了!");
}
/**
* 在所有测试之前执行
*/
@BeforeAll
static void testBeforeAll() {
log.info("要测试所有测试了!");
}
/**
* 在所有测试之后执行
*/
@AfterAll
static void testAfterAll() {
log.info("所有测试测试完了!");
}
/**
* mockmvc
*/
@Autowired
MockMvc mockMvc;
/**
* 新增用户接口测试
*
* @Disabled:该注解标识着不需要启动测试
* @Transactional:事物回滚
*/
@Disabled
@DisplayName("新增用户接口测试")
@Transactional
@Test
void saveUser() throws Exception {
// 请求地址
String urlTemplate = "/test/saveUser";
/* 请求头集合 */
HttpHeaders headers = new HttpHeaders();
headers.add("header1", "header1");
headers.add("header2", "header2");
/* 参数体 */
String uuid = UUID.randomUUID().toString();
User user = new User();
user.setId("4");
user.setFullName("copico");
user.setUserName("kebike");
user.setPassword("123456");
user.setAge(19);
user.setSex("女");
// 转换成json对象
String jsonString = JSON.toJSONString(user);
// 请求
RequestBuilder request = MockMvcRequestBuilders
// post请求
.post(urlTemplate)
// 数据类型
.contentType(MediaType.APPLICATION_JSON)
// 请求头
.headers(headers)
// 请求体
.content(jsonString);
MvcResult mvcResult = mockMvc.perform(request)
// 打印日志
.andDo(print())
// 获取返回值
.andReturn();
// 从返回值获取状态码
int status = mvcResult.getResponse().getStatus();
//从返回值获取响应的内容
String contentAsString = mvcResult.getResponse().getContentAsString();
// 断言
assertAll("heading",
() -> assertEquals(200, status, "保存失败"),
() -> assertEquals(user.toString(), contentAsString, "数据保存失败"));
}
/**
* 获取用户接口测试
*/
@DisplayName("获取用户接口测试")
@Test
void getUser() throws Exception {
// 预期结果
User user = new User("1",
"小软",
"neusoft",
"123456",null,null);
// 请求地址
String urlTemplate = "/test/getUser/1";
/* 请求头集合 */
HttpHeaders headers = new HttpHeaders();
headers.add("headers1", "headers1");
headers.add("headers2", "headers2");
LinkedMultiValueMap<String,String> linkedMultiValueMap = new LinkedMultiValueMap();
linkedMultiValueMap.add("params1", "params1");
linkedMultiValueMap.add("params2", "params2");
// 请求
RequestBuilder request = MockMvcRequestBuilders
// post请求
.get(urlTemplate)
// 数据类型
.contentType(MediaType.APPLICATION_JSON)
// 请求头
.header("header1","header1")
.headers(headers)
// 请求参数
.param("param1","param2")
.params(linkedMultiValueMap);
MvcResult mvcResult = mockMvc.perform(request)
// 打印日志
.andDo(print())
// 获取返回值
.andReturn();
// 从返回值获取状态码
int status = mvcResult.getResponse().getStatus();
//从返回值获取响应的内容
String contentAsString = mvcResult.getResponse().getContentAsString();
// 断言
assertAll("heading",
() -> assertEquals(200, status, "用户信息获取失败"),
() -> assertEquals(user.toString(), contentAsString, "数据不一致,获取失败"));
}
/**
*
* 规定方法的超时时间
* 超出时间测试异常
* @throws InterruptedException
*/
@DisplayName(value = "超出时间测试")
@Timeout(value = 500,unit = TimeUnit.MILLISECONDS)
@Test
void testTimeout() throws InterruptedException {
Thread.sleep(1000);
}
/**
* 重复测试n次
*/
@RepeatedTest(value = 2)
void repeatedTest() {
assertArrayEquals(new int[]{1, 2}, new int[]{1, 2});
}
}
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.3.9.RELEASEversion>
<relativePath/>
parent>
<groupId>com.unclegroupId>
<artifactId>junit-testartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>junit-testname>
<description>Demo project for Spring Bootdescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>fastjsonartifactId>
<version>1.2.75version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.1version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>