登录
首页 >  文章 >  java教程

SpringMockMvc删除请求测试方法

时间:2025-07-18 20:27:28 420浏览 收藏

在文章实战开发的过程中,我们经常会遇到一些这样那样的问题,然后要卡好半天,等问题解决了才发现原来一些细节知识点还是没有掌握好。今天golang学习网就整理分享《Spring MockMvc删除请求测试指南》,聊聊,希望可以帮助到正在努力赚钱的你。

Spring MockMvc REST控制器DELETE请求路径变量测试指南

本文深入探讨了使用Spring MockMvc测试REST控制器中DELETE请求时,如何正确处理路径变量,特别是针对空ID和零值ID的场景。文章详细解释了HttpRequestMethodNotSupportedException的产生原因,并提供了正确的MockMvcRequestBuilders.delete()方法使用范例,旨在帮助开发者构建健壮的单元测试,确保RESTful接口行为符合预期。

理解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学习网公众号,带你了解更多关于的知识点!

相关阅读
更多>
最新阅读
更多>
课程推荐
更多>