Spring MockMvc如何测试REST Controller中ID为空的DELETE请求?
问题分析
你遇到的500错误核心原因是:当传入空字符串作为id时,MockMvc构造的请求URL变成了/api/wallet/,而你的控制器只映射了/api/wallet/{id}这个带路径变量的DELETE接口。Spring找不到匹配的处理方法,抛出HttpRequestMethodNotSupportedException,如果没有全局异常处理兜底,就会返回500状态码,而不是预期的参数校验错误。
下面针对你要测试的两个场景,给出具体的解决方案:
场景1:测试ID为空字符串(路径变量存在但为空)
要触发参数绑定错误(空字符串无法转换为Long类型),你需要构造包含空路径段的请求,同时确保Spring能匹配到控制器方法。另外注意:DELETE请求通常不需要请求体,测试代码里可以去掉冗余的content()相关逻辑:
@Test void shouldThrowBadRequestWhenWalletIdIsEmptyString() throws Exception { // 构造URL为/api/wallet/(空路径段作为id) ResultActions result = mockMvc.perform(delete("/api/wallet/{id}", "") .contentType(MediaType.APPLICATION_JSON)); // 空字符串转Long失败,预期返回400 Bad Request result.andExpect(status().isBadRequest()); }
如果这个请求还是匹配不到控制器方法,可以调整Spring的路径匹配配置,允许空路径变量:
@Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { configurer.setUseTrailingSlashMatch(true); } }
场景2:测试ID等于0
这个场景很直接,构造路径变量为0的请求即可,此时会触发@Min(1)的校验规则,返回400错误:
@Test void shouldThrowBadRequestWhenWalletIdIsZero() throws Exception { ResultActions result = mockMvc.perform(delete("/api/wallet/{id}", 0) .contentType(MediaType.APPLICATION_JSON)); result.andExpect(status().isBadRequest()) // 可选:如果有全局异常处理返回校验信息,可以额外断言错误内容 .andExpect(jsonPath("$.message").value("must be greater than or equal to 1")); }
额外优化建议
- 移除冗余请求体:你的DELETE接口没有接收请求体的参数,测试代码里完全可以去掉
content()和objectMapper相关的逻辑,简化测试。 - 添加全局异常处理:统一处理各类异常,让状态码更符合REST规范,比如给
HttpRequestMethodNotSupportedException返回405,给校验异常返回400:
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public ResponseEntity<String> handleMethodNotAllowed(HttpRequestMethodNotSupportedException ex) { return new ResponseEntity<>("请求方法不支持", HttpStatus.METHOD_NOT_ALLOWED); } @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<Map<String, String>> handleConstraintViolation(ConstraintViolationException ex) { Map<String, String> errors = new HashMap<>(); ex.getConstraintViolations().forEach(violation -> { String field = violation.getPropertyPath().toString(); errors.put(field, violation.getMessage()); }); return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); } @ExceptionHandler(TypeMismatchException.class) public ResponseEntity<String> handleTypeMismatch(TypeMismatchException ex) { return new ResponseEntity<>("参数类型无效", HttpStatus.BAD_REQUEST); } }
这样调整后,无论是方法不支持还是参数错误,都会返回符合预期的状态码,测试结果也会更准确。
内容的提问来源于stack exchange,提问作者RobertoJavaDev
相关产品推荐
相关产品推荐

