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

如何在不使用@SpringBootTest的情况下轻量化测试Spring Boot控制器?

轻量化控制器测试的两种方案

1. 基于Spring Web层上下文的集成测试:@WebMvcTest

这个注解专门为Web控制器测试设计,只会加载与Web层相关的Bean(比如控制器、请求映射处理器、参数校验器等),不会加载整个应用的业务层、持久层组件,启动速度比@SpringBootTest快得多,完美解决你遇到的5秒启动耗时问题。

改造后的测试代码示例:

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 static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

@WebMvcTest(ChoreController.class) // 仅加载指定的控制器类
public class ChoreControllerTest {

    @Autowired
    private ChoreController controller; // 直接注入控制器实例

    @MockBean // 模拟控制器依赖的业务服务,解决NPE问题
    private ChoreService choreService;

    @Test
    public void throwOnMissingChore() {
        // 预设服务层的行为:当传入0L时抛出异常
        when(choreService.getChore(0L)).thenThrow(new ChoreNotFoundException());
        
        assertThrows(ChoreNotFoundException.class, () -> this.controller.getChore(0L));
    }
}
  • 为什么不会NPE:@MockBean会自动创建一个模拟的ChoreService实例,并注入到控制器中,填补了依赖缺失的空白。
  • 额外能力:如果需要测试完整的HTTP请求流程(比如URL映射、JSON序列化、HTTP状态码返回等),还可以用MockMvc模拟请求:
    @Autowired
    private MockMvc mockMvc;
    
    @Test
    public void throwOnMissingChoreViaMockMvc() throws Exception {
        when(choreService.getChore(0L)).thenThrow(new ChoreNotFoundException());
        
        mockMvc.perform(get("/chores/0"))
               .andExpect(status().isNotFound());
    }
    

2. 纯单元测试:完全跳过Spring上下文

如果你的测试只关注控制器内部的逻辑处理(不需要验证Web层的特性),可以用Mockito直接模拟依赖,完全不启动Spring,测试执行时间几乎可以忽略。

代码示例:

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;

@ExtendWith(MockitoExtension.class) // 启用Mockito扩展
public class ChoreControllerTest {

    @Mock // 模拟控制器依赖的业务服务
    private ChoreService choreService;

    @InjectMocks // 自动将模拟服务注入到控制器实例中
    private ChoreController controller;

    @Test
    public void throwOnMissingChore() {
        when(choreService.getChore(0L)).thenThrow(new ChoreNotFoundException());
        
        assertThrows(ChoreNotFoundException.class, () -> controller.getChore(0L));
    }
}
  • 优势:完全避免Spring上下文启动的开销,测试速度最快。
  • 适用场景:只验证控制器的逻辑分支、参数处理等,不需要测试Web层的请求响应流程。

测试多个控制器时的耗时优化

如果要测试多个控制器,核心思路是复用Spring上下文,避免重复加载的开销:

  1. 共享@WebMvcTest配置:如果多个控制器的测试类使用相同的@WebMvcTest参数(比如一次性指定多个控制器),Spring会自动缓存上下文,后续测试类直接复用,不需要重新加载:

    @WebMvcTest({ChoreController.class, UserController.class, TaskController.class})
    public class MultiControllerTest {
        // 在这里编写多个控制器的测试用例
    }
    

    即使分开写测试类,只要每个类的@WebMvcTest配置一致(比如没有额外的@Import或自定义配置),Spring也会自动缓存上下文,第二次及以后的测试启动速度会大幅提升。

  2. 分组功能相关测试:把业务关联的控制器测试放在同一个测试类中,减少上下文的加载次数。

  3. 优先纯单元测试:对于不需要Web层特性的控制器测试,尽量用Mockito的纯单元测试方式,完全跳过Spring上下文的启动开销。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 19:07:48