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

@WebMvcTest测试中如何注入真实Service实例解决覆盖率问题

问题说明

针对MyController.java编写的@WebMvcTest测试代码如下:

@WebMvcTest(controllers = MyController.class)
class MyControllerTest {
  @Autowired 
  private MockMvc mockMvc;
  @MockBean 
  private SomeService service; //dependency of MyService
  @SpyBean 
  private MyService myService; //used in MyController
  @Test
  void testMyControllerCall() {
    //someTest
  }
}

存在的现象与需求:

  • 给MyService添加@SpyBean注解时,虽然可以调用真实服务逻辑并将Bean注入MyController,但运行测试覆盖率统计时,MyService的代码不会被标记为已覆盖
  • 需要在测试类中向MyController注入常规(非Mock、非Spy)的MyService真实实现
  • 不接受将MyControllerTest移动到test/java/controller包外的方案,需要保留测试类在对应包下维持代码结构规整

当前项目目录结构:

> main/java
> --/controller
> ----/MyController.java
> --/service
> ----/MyService.java 
> test/java
> --/controller
> ----/MyControllerTest.java
解决方法

@WebMvcTest属于Web层切片测试,默认只会加载Controller层相关的Bean,Service层Bean不会被自动注册到测试上下文。之前使用@SpyBean、@MockBean注入的对象会经过Mock代理增强,覆盖率工具无法识别代理背后真实类的执行路径,因此不会统计对应代码的覆盖率。

按以下步骤修改即可:

  1. 移除MyService上的@SpyBean注解
  2. 在测试类上添加@Import(MyService.class)注解,显式将MyService的原生真实实现导入测试上下文
  3. 直接通过@Autowired注入MyService即可,不需要添加任何Mock/Spy相关注解

修改后的测试代码示例:

@WebMvcTest(controllers = MyController.class)
@Import(MyService.class) // 显式导入原生MyService真实实现,无代理增强
class MyControllerTest {
  @Autowired 
  private MockMvc mockMvc;
  @MockBean 
  private SomeService service; // 继续Mock MyService依赖的外部组件
  @Autowired
  private MyService myService; // 直接注入真实实现

  @Test
  void testMyControllerCall() {
    // 编写测试逻辑
  }
}

该方案的优势:

  • 导入的MyService是Spring初始化的原生Bean,没有Mock/Spy代理层,覆盖率工具可以正常识别代码执行路径,准确统计覆盖率
  • 不需要调整测试类的存放位置,完全匹配原有目录结构规范
  • 如果MyService后续新增其他需要Mock的依赖,直接在测试类中添加对应@MockBean即可,不会影响MyService真实Bean的注入逻辑

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 16:42:53