首页 > 解决方案 > 在 Spring MVC 中对控制器类进行单元测试是一种好习惯吗

问题描述

我曾经像任何其他普通 Java 类一样对我的控制器类进行单元测试。我的意思是不使用 Spring 的 MockMvc。但后来我意识到,这样我将无法确定我是否正确设置了 MVC 配置。所以如果我有这样的控制器:

@Restcontroller
@RequestMapping("/cars")
public class CarController{
    private CarService carService;
    public CarController (CarService service){this.carService = service};
    @GetMapping
    public List<Car> getCar(@RequestParam("filter") String filter){
       if(filter!=null && !filter.trim().equal("")){
          //omitted for brevity
       }
    }
}

如果我getCar直接对其方法进行单元测试,即使测试通过,也不意味着我的控制器没问题。因此,我没有进行单元测试,而是开始实际进行集成测试。像这样的东西:

mockMvc.perform(get("/v1/cars?filter = Honda"))....  bla bla bla

最近出现了一个问题,我们是否应该首先进行单元测试和集成测试休息控制器。乍一看,在我看来,集成测试最终会检查控制器的正确行为。但另一方面,仅依靠集成测试有多好。

标签: springunit-testingcontrollerintegration-testing

解决方案


我个人从来没有发现单元测试控制器有用。在理想情况下,Controller 是相对苗条的,因为它只调用服务对象的几个方法并返回结果。IMO 单元测试将意味着(过度)使用该verify()方法。(即控制器是否使用正确的参数调用了服务方法。)

例如,在我的例子中,一个编写良好的控制器方法如下所示:

@LoggingInfo
  @PostMapping(value = "/someRoute",
      produces = "application/json",
      consumes = "application/json")
  @ApiOperation(value = "Some description", response = SomeDTO.class)
  public @ResponseBody
  CompletableFuture<ResponseEntity> someControllerMethod(
      @Validated(ValidationSequence.class) @RequestBody SomeDTO someDTO) {

    return service
        .doSomething(someDTO)
        .thenApply((String var) -> ResponseEntity.ok(ResponseDTO.builder()
            .myField(Collections.singleton(var)).build()));
  }

对这种方法进行单元测试会在多大程度上为应用程序增加价值?

对我来说,改变游戏规则的是集成测试的使用。事实证明,如果所有弹簧魔法都正常工作,例如:

  • 由注释触发的验证器
  • (不同)验证器的顺序
  • 转换器(即见杰克逊在行动)
  • 异常处理程序(被注释的异常处理程序实际捕获的抛出异常)

希望这可以帮助。


推荐阅读