MockMvc 接口测试与测试切片

接口写完后要能快速回归。MockMvc 由 spring-test 提供,不真正启动 Servlet 容器,直接向 DispatcherServlet 发起带 HTTP 语义的请求并断言响应,跑得快、适合进 CI,是 Spring Boot Web 层测试最常用的手段。本章示例基于 Spring Boot 3.x(3.5 主线;4.0 已于 2025-11 发布,多数存量工程仍用 3.x)。

起步:@SpringBootTest + @AutoConfigureMockMvc

引入测试依赖(Boot 父 POM 统一管版本,聚合 JUnit5、AssertJ、Mockito、JSONassert):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

全量上下文 + MockMvc 的经典写法:

@SpringBootTest                 // 加载完整应用上下文
@AutoConfigureMockMvc           // 自动装配 MockMvc Bean
class UserControllerTest {
    @Autowired
    MockMvc mockMvc;

    @Test
    void getUser_shouldReturn200() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.get("/api/users/1"))
               .andExpect(MockMvcResultMatchers.status().isOk())
               .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("张三"));
        // 输出:HTTP 200,且响应 JSON 的 name 字段为「张三」
    }
}

perform 发起请求,andExpect 逐条断言;jsonPath("$.name") 用 JSONPath 语法取字段,andReturn 可拿到完整响应体再做自定义校验。

POST 与 JSON、CSRF 处理

一旦 classpath 里有 spring-security(见第 29 章),写操作默认要求 CSRF 令牌,测试里要带上:

mockMvc.perform(post("/api/users")
        .contentType(MediaType.APPLICATION_JSON)
        .content("{\"name\":\"李四\",\"email\":\"li@example.com\"}")
        .with(SecurityMockMvcRequestPostProcessors.csrf()))   // 附加 CSRF 令牌
       .andExpect(status().isCreated())
       .andExpect(jsonPath("$.id").exists());

测试切片:@WebMvcTest

切片(slice)只加载某一层所需 Bean,上下文小、启动快。@WebMvcTest 只装配 Controller、@ControllerAdvice 与 MVC 基础组件,Service 用测试替身打桩:

@WebMvcTest(UserController.class)      // 只加载 Web 层
class UserControllerSliceTest {
    @Autowired
    MockMvc mockMvc;

    @MockitoBean                        // Boot 3.4+ 推荐写法;旧注解 @MockBean 已弃用
    UserService userService;

    @Test
    void get_shouldCallService() throws Exception {
        when(userService.findById(1L)).thenReturn(new UserDto(1L, "张三"));

        mockMvc.perform(get("/api/users/1"))
               .andExpect(status().isOk())
               .andExpect(jsonPath("$.name").value("张三"));
    }
}

其他常用切片:@DataJpaTest(仅 JPA Repository)、@JsonTest(仅 JSON 序列化)、@RestClientTest(仅 RestClient/WebClient 配置)。切片打桩后断言的只是"自己这层逻辑",全链路正确性交给集成测试(第 25 章)。

切片与全量测试如何选

  • 纯 Controller 分支、参数映射、校验提示 → @WebMvcTest,最快;
  • 涉及 AOP、事务、跨层联动 → @SpringBootTest 全量;
  • 真实网络端口场景 → @SpringBootTest(webEnvironment = RANDOM_PORT) 配合 TestRestTemplate 或 WebTestClient。

小结:单测 Web 层优先 @WebMvcTest + @MockitoBean,全链路用 @SpringBootTest + MockMvc;带 Security 时 POST 请求记得补 CSRF 令牌。

笔记加载中…