SpringMockMvc删除请求测试教程
本文深入解析了在Spring MockMvc中测试DELETE请求时,如何正确处理路径变量,特别是针对空ID和零值ID的场景。文章着重强调了`HttpRequestMethodNotSupportedException`的产生原因,并提供了`MockMvcRequestBuilders.delete()`方法的正确使用姿势。通过示例代码,展示了如何针对带`@PathVariable`的RESTful接口编写健壮的单元测试,包括测试ID为零的情况以及模拟“空ID”场景。 此外,还强调了路径变量验证的重要性,并建议在测试中覆盖有效ID、不存在的ID、格式错误的ID以及权限问题等多个方面,旨在帮助开发者构建高质量的Spring Boot应用,确保RESTful接口在各种边界条件下都能按预期工作,避免常见的404或405错误。

理解Spring MockMvc中的路径变量测试
在Spring Boot应用中,我们经常使用@PathVariable来从URL路径中提取参数。例如,一个删除钱包的API可能定义为@DeleteMapping("/{id}"),这意味着它期望一个非空的id作为路径的一部分。当使用MockMvc进行测试时,如果不正确地构造请求路径,可能会遇到HttpRequestMethodNotSupportedException。
问题根源分析: 原始测试代码中的delete("/api/wallet/{}", id),当id为一个空字符串时,最终生成的请求URL是/api/wallet/。然而,控制器中定义的映射是@DeleteMapping("/{id}"),它期望一个具体的id值(例如/api/wallet/1)。/api/wallet/这个路径与/{id}模式不匹配。Spring MVC会尝试查找是否有其他方法(例如GET /api/wallet)映射到/api/wallet/这个路径。如果找到了一个映射(即使是GET方法),但该映射不支持DELETE请求,就会抛出HttpRequestMethodNotSupportedException。本质上,这不是因为ID为空导致的问题,而是因为请求的URL路径与预期的@DeleteMapping("/{id}")不匹配,导致Spring寻找其他可能匹配的处理器,并发现它们不支持DELETE方法。如果没有任何方法映射到/api/wallet/,那么将返回404 Not Found。
正确测试带路径变量的DELETE请求
MockMvcRequestBuilders.delete()方法在处理路径变量时,应使用占位符{}并提供相应的参数值。Spring MockMvc会负责将这些值正确地插入到URL中。
1. 测试ID为零(或任何有效数字)的情况: 当需要测试ID为特定数值(如0或1)时,应该将该数值作为delete()方法的额外参数传入,让其填充URL模板中的占位符。
示例:测试ID为0
假设我们要测试删除ID为0的钱包,根据控制器中的@Min(1)注解,这应该导致一个BadRequest错误。
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import java.time.Instant;
import java.util.Objects;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
// 假设 WalletController 和 WalletService 已经定义
// 这里只展示测试相关的部分
@WebMvcTest(WalletController.class) // 针对 WalletController 进行Web层测试
class WalletControllerTest {
@MockBean
private WalletService walletService; // 模拟 WalletService
@Autowired
private MockMvc mockMvc; // 注入 MockMvc
@Autowired
private ObjectMapper objectMapper; // 注入 ObjectMapper
// 假设 WalletDTO 已经定义
static class WalletDTO {
private Long id;
private String name;
private Instant creationDate;
public WalletDTO(Long id, String name, Instant creationDate) {
this.id = id;
this.name = name;
this.creationDate = creationDate;
}
// Getters and Setters
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Instant getCreationDate() { return creationDate; }
public void setCreationDate(Instant creationDate) { this.creationDate = creationDate; }
}
// 假设 WalletController 如下定义
// @RestController
// @RequestMapping("api/wallet")
// @RequiredArgsConstructor
// @Validated
// public class WalletController {
// private final WalletService walletService;
// @DeleteMapping("/{id}")
// public ResponseEntity deleteWalletById(@Valid @Min(1) @PathVariable Long id) {
// walletService.deleteWalletById(id);
// HttpHeaders headers = new HttpHeaders();
// headers.add("message", "You have successfully completed the delete of a Wallet!");
// return new ResponseEntity<>(headers, HttpStatus.OK);
// }
// }
@Test
void shouldThrowBadRequestWhenWalletIdIsZero() throws Exception {
// given
// 对于路径变量测试,通常不需要请求体内容,因为DELETE操作主要依赖ID
// 如果你的DELETE方法也需要请求体,则保留 content()
// WalletDTO walletDTO = new WalletDTO(1L, "Default", Instant.now());
Long id = 0L; // 测试 ID 为 0
// when
ResultActions result = mockMvc.perform(delete("/api/wallet/{id}", id) // 正确使用路径变量
.contentType(MediaType.APPLICATION_JSON)); // contentType 在DELETE请求中通常不是必需的,除非请求体有内容
// then
result.andExpect(status().isBadRequest()); // 期望 BadRequest 状态码,因为 @Min(1) 校验失败
}
} 在上述代码中,delete("/api/wallet/{id}", id)会正确地将id变量的值(例如0L)替换到{id}占位符中,从而生成请求URL /api/wallet/0。这样,请求就能正确地匹配到@DeleteMapping("/{id}")方法,并触发其内部的@Min(1)验证。
处理“空ID”场景的特殊性
测试“空ID”是一个更复杂的问题,因为它通常意味着请求的URL结构发生了变化,而不是仅仅传递了一个空字符串作为参数值。
分析: 如果控制器定义为@DeleteMapping("/{id}"),那么请求/api/wallet/(即{id}为空)将无法匹配此映射。
- 情况一: 如果你的应用中没有任何映射(无论是GET、POST还是DELETE)是针对/api/wallet/这个路径的,那么请求/api/wallet/将直接导致404 Not Found。
- 情况二: 如果你的应用中存在其他HTTP方法的映射,例如@GetMapping("/api/wallet"),那么当请求DELETE /api/wallet/时,Spring MVC会找到@GetMapping("/api/wallet")这个映射,但发现它不支持DELETE方法,从而抛出HttpRequestMethodNotSupportedException(如原始问题所示)。
如何模拟和测试“空ID”场景:
如果你确实想测试当路径变量为空时,系统如何响应(例如,是否返回404或400),你需要直接构建一个不包含路径变量的URL。
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
// ... 其他导入和类定义 ...
@Test
void shouldReturnNotFoundOrMethodNotAllowedWhenWalletIdIsEmptyStringInPath() throws Exception {
// 当你想测试 /api/wallet/ 这种没有ID的路径时
// 直接构建该URL,而不是通过路径变量的方式
ResultActions result = mockMvc.perform(delete("/api/wallet/") // 直接请求 /api/wallet/
.contentType(MediaType.APPLICATION_JSON));
// 根据你的应用设计,这里可能期望 404 Not Found 或 405 Method Not Allowed
// 如果存在 GET /api/wallet 这样的映射,则可能是 405 (Method Not Allowed)
// 如果没有任何映射,则通常是 404 (Not Found)
result.andExpect(status().isNotFound()); // 或 .isMethodNotAllowed()
}注意事项:
- 路径变量的验证: 控制器中@Min(1)这样的验证注解非常重要。它确保了只有符合业务逻辑的ID才会被处理。测试时应充分覆盖这些验证规则。
- 测试覆盖: 针对DELETE请求,除了有效ID、零值ID和空ID(即无ID)的测试外,还应考虑:
- 不存在的ID: 期望404 Not Found。
- 格式错误的ID: 例如delete("/api/wallet/{id}", "abc"),这通常会导致400 Bad Request(类型转换失败)。
- 权限问题: 如果有安全机制,测试未授权用户尝试删除的情况。
总结
在Spring MockMvc中测试REST控制器时,正确理解和使用MockMvcRequestBuilders中的路径变量占位符至关重要。对于@DeleteMapping("/{id}")这类带路径变量的接口,应始终使用delete("/path/{id}", value)的格式来传递ID值。如果需要测试“空ID”或缺少ID的场景,应直接构造对应的URL路径(例如/api/wallet/),而不是试图将空字符串传入路径变量占位符,因为这会改变请求的实际URL结构,可能导致不同的错误响应,如404 Not Found或405 Method Not Allowed。通过细致地构建测试用例,我们可以确保RESTful API在各种边界条件下都能按预期工作。
理论要掌握,实操不能落!以上关于《SpringMockMvc删除请求测试教程》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!
中国风AI视频工具推荐与评测
- 上一篇
- 中国风AI视频工具推荐与评测
- 下一篇
- 通义千问热点稿件实测与分析
-
- 文章 · java教程 | 4小时前 | 性能优化 · Java教程 · CompletableFuture · 接口聚合 · java completablefuture orTimeout completeOnTimeout 接口性能 P95
- Java CompletableFuture 聚合接口优化:用超时兜底把 P95 从 920ms 降到 330ms
- 255浏览 收藏
-
- 文章 · java教程 | 23小时前 | Spring Boot · Java教程 · 接口设计 · Webhook · 幂等设计 · java spring boot WebHook 回调接口 幂等 状态流转 验签
- Java Webhook 回调接收接口设计:验签、幂等和状态流转
- 488浏览 收藏
-
- 文章 · java教程 | 2天前 | Java教程 · TTL缓存 · ConcurrentHashMap · 小项目 · java 本地缓存 concurrenthashmap TTL缓存 过期淘汰
- Java 本地 TTL 缓存小项目:用 ConcurrentHashMap 实现过期淘汰和命中统计
- 394浏览 收藏
-
- 文章 · java教程 | 2天前 | Java · Stream · 数据处理 · 后端教程 · Java Stream bigdecimal 分组统计 Collectors 订单汇总
- Java Stream 分组统计实验:从订单列表到客户消费汇总
- 355浏览 收藏
-
- 文章 · java教程 | 2天前 | Java · Spring Boot · 后端开发 · 接口校验 · java spring boot dto 接口设计 参数校验
- Spring Boot 参数校验工作流:DTO、注解和统一错误响应
- 495浏览 收藏
-
- 文章 · java教程 | 2星期前 | map · 并发安全 · 缓存设计 · Java教程 · java optional concurrenthashmap computeIfAbsent Map缓存
- Java computeIfAbsent 缓存初始化实战:少写判断、避开空值和并发坑
- 236浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ljg-skills
- ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
- 2968次使用
-
- MELO音乐
- MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
- 2742次使用
-
- UniScribe
- UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
- 2679次使用
-
- 剧云
- 剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
- 2912次使用
-
- 万象有声
- 万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
- 2860次使用
-
- 矩阵主副对角线快速定位技巧
- 2026-05-31 501浏览
-
- Java多态优化流程代码与行为分发改进
- 2026-05-26 501浏览
-
- JVM 类元数据双亲委派链表深度解析
- 2026-05-21 501浏览
-
- 反射异常处理:InvocationTargetException解析与应用
- 2026-05-16 501浏览
-
- 怎么通过 HTML 的 accesskey 属性为网页中的按钮或链接设置键盘快捷键
- 2026-05-04 501浏览

