栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

基于 mockMvc 的 Controller 层单元测试

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

基于 mockMvc 的 Controller 层单元测试

场景

单元测试是个让人很纠结的东东,dealline 催的很紧,不想写单测,但当项目复杂到一定程度需要重构时,返现没有单测,不敢随便改代码,生怕”敲一锤子,倒一大片“,但此时再补,已经有点晚了。磨刀不误砍柴功,这会偷的懒后面总要跟你算账的,所以还乖乖写吧。

单测目的

这个很重要,不清楚目的,就不知道接下来该怎么做。这样也行,那样好像也可以,埋头写一大片,很快就没了兴趣,而且还会很烦写单测。常见 web 服务大都是 controller、service、repository 三层架构。每一层都有各自的任务,基于此单测的目的也就不同。

repository 层主要负责数据的持久化,它里面除了读和写,其他的逻辑越少越好。所以该层单测要连上数据库,将数据真正的写入并且读出,从而确认该数据持久化,以及各种查找功能正确。推荐持久化层单测内嵌 H2 数据库,它是基于内存的,不受物理机限制,而且各个单测 case 之间互无影响。service 层负责处理业务逻辑,很复杂的项目往往也就是复杂在这一层了,这层肯定会依赖该项目的 repository 层,还可能会依赖 Redis、kafka、mq、httpClinet 等第三方的东西。每次单测都调用第三方,哪有那么听话的第三方,每次都能正确返回结果。这层单测怎么写?把 service 层依赖的 repository 和 第三方的东西都 mock 出来,并 when 他们对应的方法,按照测试需求控制其方法返回值,从而控制 service 层的方法中代码的走向,确认自己写的逻辑是没问题的。在这一层中,一个方法往往需要好几个测试 case,一个正例,若干的异常情况。controller 层负责和前端交互,接收请求、校验参数、返回处理结果。最理想的单测肯定是模拟出生产环境下前端请求的执行。这是可以办到的。

三层单测有各自的目的,而且不依赖于其余两层,如果真依赖了,那就使用 mock,控制返回值。从而实现“隔离”,本层单测只需要实现本层的目的,其余的都是不需要知道的。

controller 层单测

mockMVC 可以实现在单测中模拟生产环境中前端请求的执行逻辑。

Controller:

@RestController
@RequestMapping("/trains")
public class TrainController {

    private TrainService trainService;

    @Autowired
    public TrainController(TrainService trainService) {
        this.trainService = trainService;
    }

    @PostMapping("")
    public void create(@RequestBody @Validated ModelTrainsAddDTO req) {
        TrainEntity entity = new TrainEntity();
        BeanUtils.copyProperties(req, entity);
        trainService.create(entity);
    }
}

@Data
@NoArgsConstructor
@AllArgsConstructor
public class ModelTrainsAddDTO {
    @NotBlank
    private String name;
    private String modelType;
}

单元测试

@WebMvcTest(TrainController.class)
class TrainControllerTest {
    @MockBean
    private TrainService trainService;

    @Autowired
    private MockMvc mockMvc;

    @BeforeEach
    void setUp() {
        RestAssuredMockMvc.mockMvc(mockMvc);
    }

    @Test
    void should_200_if_create_train_succeed() {
        ModelTrainsAddDTO param = new ModelTrainsAddDTO("name", "model-type", "trian-fileds", "evail-files", "param");
        given()
                .contentType(ContentType.JSON)
                .body(param)
                .when()
                .post("/trains")
                .prettyPeek()
                .then()
                .statusCode(200);

        verify(trainService).create(any());
    }

    // 注解校验没通过,直接抛异常。
    @Test
    void should_500_if_name_is_null_when_create_train() {
        ModelTrainsAddDTO param = new ModelTrainsAddDTO(null, "model-type", "trian-fileds", "evail-files", "param");

        given()
                .contentType(ContentType.JSON)
                .body(param)
                .when()
                .post("/trains")
                .prettyPeek()
                .then()
                .statusCode(500);
    }
}
RestAssuredMockMvc

RestAssuredMockMvc 详细使用方法在这里,需要科学上网。它采用熟悉的 given-when-then 的场景格式定义测试写法,里面有段这样的描述:

given() — specifies the HTTP request details
when() — specifies the HTTP verb as well as the route
then() — validates the HTTP response

当然也还有别的写法,比如:mockMvc.perform()。

依赖

	io.rest-assured
  spring-mock-mvc
  4.5.1
  test

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/754739.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号