背景
最近换工作要写 SpringBoot Controller 层测试类。看了很多资料才找到,直接上看代码
代码
- 脱敏
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import lombok.Data;
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.test.web.servlet.MockMvc;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
@SpringBootTest(classes = BackstageWebApiStart.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@DisplayName("测试 RoleController")
class RoleControllerTest {
/** 第一条数据下标 */
private static final int FIRST = 0;
/** 日期处理 */
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/** 自增变量,区别 name */
private static int CONSTANT = 0;
/** 插入参数 */
private static TestRoleDTO insertRoleDTO;
/** 用于转化的角色Gson,角色类型特殊处理 */
private static final Gson ROLE_GSON;
static {
ROLE_GSON = new GsonBuilder()
.registerTypeAdapter(RoleType.class,new RoleTypeSerializer())
.create();
}
@Autowired
private MockMvc mockMvc;
/**
* 测试新增
*/
@Test
@Order(1)
void save() throws Exception {
log("新增");
TestRoleDTO testRoleDTO = initTestRoleDTO();
String insertGson = ROLE_GSON.toJson(testRoleDTO.getRoleDTO());
long id = TestMethodUtil.testPostRequest(mockMvc, "/backstage/api/v1/role/new", insertGson);
Assertions.assertTrue(id > 0,"新增返回 id 要大于零");
//保存新增信息
insertRoleDTO = testRoleDTO;
insertRoleDTO.setId(id);
System.out.println("save param : " + testRoleDTO);
}
/***
* 初始化角色对象
*/
private TestRoleDTO initTestRoleDTO(){
int constant = ++CONSTANT;
TestRoleDTO testRoleDTO = new TestRoleDTO();
Date now = new Date();
RoleDTO roleDTO = new RoleDTO();
roleDTO.setName("RoleControllerTest - " + DATE_FORMAT.format(now) + "-" + constant );
roleDTO.setRemark("controllerTestRemark" + DATE_FORMAT.format(now) + "-" + constant);
roleDTO.setType(RoleType.Normal);
testRoleDTO.setRoleDTO(roleDTO);
return testRoleDTO;
}
/**
实体类
*/
@Data
private static class TestRoleDTO{
private Long id;
private RoleDTO roleDTO;
}
/***
* Gson 处理角色类型转换
*/
private static class RoleTypeSerializer implements JsonSerializer<RoleType>, JsonDeserializer<RoleType>{
@Override
public RoleType deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
return RoleType.getRoleTypeByValue(jsonElement.getAsInt());
}
@Override
public JsonElement serialize(RoleType roleType, Type type, JsonSerializationContext jsonSerializationContext) {
return new JsonPrimitive(Integer.valueOf(roleType.getValue()).toString());
}
}
}
工具类脱密代码
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
/**
* Created on 2021/4/30 18:11
* 请求工具类
* @author Xuan
*/
public class TestMethodUtil {
/** UTF-8 编码*/
private static final String UTF8 = "UTF-8";
/** 类型转换 */
private static final Gson GSON = new Gson();
/**
* 测试 post 请求
*/
public static long testPostRequest(MockMvc mockMvc, String uri, String postParam) throws Exception {
MvcResult mvcResult = mockMvc
.perform(
MockMvcRequestBuilders
.post(uri)
.contentType(MediaType.APPLICATION_JSON)
.content(postParam))
// .andDo(MockMvcResultHandlers.print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andReturn();
MockHttpServletResponse responseContent = mvcResult.getResponse();
responseContent.setCharacterEncoding(UTF8);
ResponseResult<Long> responseResult = GSON.fromJson(responseContent.getContentAsString(),
new TypeToken<ResponseResult<Long>>(){}.getType());
return responseResult.getResult();
}
- 把入参的 DTO 又包装成了 TestDTO,方便测试。最后可以把打印出来的实例与数据库数据对比,查看正确性。
其实还可以再写一个测试方法,把入参和查询的结果对比,来进行简单的自动化测试
由于太长就不上传了,提供一个思路。
遇到问题
原因是:
- 原来
@SpringBootTest(classes = BackstageWebApiStart.class)
- 少了 webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,最终应该是
@SpringBootTest(classes = BackstageWebApiStart.class,webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
在百度中有解释,大概原因是不加 SpringBootTest.WebEnvironment.RANDOM_PORT 时,阿里 druid 某些类没有初始化(过滤器):https://github.com/alibaba/druid/issues/2050