You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

测试RestController Delete方法返回404(预期400),测试方法异常

排查与解决:测试shouldNotDeletePersonByGivenId返回404而非预期400的问题

你的测试出现预期状态码不匹配的问题,我帮你梳理几个核心排查方向和对应的解决办法:

1. 先确认控制器路径是否匹配

404状态码最直接的原因是请求路径找不到对应的控制器方法,你需要检查:

  • 你的Person控制器类上是否标注了@RestController+@RequestMapping("/persons")
  • 删除方法是否标注了@DeleteMapping("/{id}")(如果类上已有@RequestMapping("/persons"),方法上的@DeleteMapping可以直接写@DeleteMapping或@DeleteMapping("/{id}"),确保和测试中的/persons/{id}路径完全匹配)

如果路径不匹配,请求会直接返回404,和服务层的异常逻辑无关。

2. 检查控制器删除逻辑是否提前拦截了请求

如果控制器在调用服务层deleteById之前,自行做了实体存在性检查并返回404,那你的mock异常逻辑根本不会被触发。比如这种情况:

@DeleteMapping("/{id}")
public ResponseEntity<Void> deletePerson(@PathVariable Long id) {
    // 提前检查实体,不存在直接返回404
    Person person = personService.findById(id);
    if (person == null) {
        return ResponseEntity.notFound().build();
    }
    personService.deleteById(id);
    return ResponseEntity.noContent().build();
}

如果是这种情况,你需要修改控制器逻辑,把实体存在性检查交给服务层的deleteById方法处理(让deleteById在找不到实体时抛出NoEntityFoundException),控制器只负责调用服务层方法即可:

@DeleteMapping("/{id}")
public ResponseEntity<Void> deletePerson(@PathVariable Long id) {
    personService.deleteById(id);
    return ResponseEntity.noContent().build();
}

3. 配置异常映射,将自定义异常关联到400状态码

Spring默认不会把自定义RuntimeException自动映射为400 Bad Request,通常会返回500 Internal Server Error。你需要添加异常处理逻辑来指定这个异常对应的状态码:

方案一:全局异常处理器(推荐,适用于所有控制器)

创建一个全局异常处理类,捕获NoEntityFoundException并返回400:

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(PersonService.NoEntityFoundException.class)
    public ResponseEntity<String> handleNoEntityFoundException(PersonService.NoEntityFoundException ex) {
        return new ResponseEntity<>(ex.getMessage(), HttpStatus.BAD_REQUEST);
    }
}

方案二:控制器局部异常处理

如果只需要在当前控制器处理这个异常,可以在Person控制器中添加@ExceptionHandler方法:

@RestController
@RequestMapping("/persons")
public class PersonController {

    // 注入personService...

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deletePerson(@PathVariable Long id) {
        personService.deleteById(id);
        return ResponseEntity.noContent().build();
    }

    @ExceptionHandler(PersonService.NoEntityFoundException.class)
    public ResponseEntity<String> handleNoEntityFound(PersonService.NoEntityFoundException ex) {
        return ResponseEntity.badRequest().body(ex.getMessage());
    }
}

4. 验证Mock的参数匹配是否正确

检查你的mock语句:

Mockito.doThrow(new PersonService.NoEntityFoundException())
       .when(personService).deleteById(1L);

这里你mock的是deleteById(1L)(Long类型的1),而测试请求传入的是1(Integer类型)。如果控制器的@PathVariable参数是Long id,Spring会自动把Integer的1转为Long的1L,参数匹配没问题;但如果控制器参数是Integer id,服务层deleteById接收的是Integer类型,你的mock就不匹配(因为mock的是Long类型参数),此时服务层不会抛出异常,可能导致控制器返回非预期状态码。

确保控制器路径参数类型和服务层方法参数类型一致即可。

按照上面的步骤排查后,你的测试应该就能正确返回400状态码了。

内容的提问来源于stack exchange,提问作者Magdalena Rumakowicz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:53:38