一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Spring Boot集成测试中Mockito模拟对象返回null的解决办法

时间:2026-07-11 09:36:02 编辑:袖梨 来源:一聚教程网

在spring boot集成测试中,若同时使用@springboottest和@extendwith(mockitoextension.class),直接用@mock声明依赖对象却未正确关联到被测类,会导致模拟失效(如userinfodto为null);根本原因在于混淆了spring容器管理与纯mockito测试的上下文机制。

在spring boot集成测试中,若同时使用@springboottest和@extendwith(mockitoextension.class),直接用@mock声明依赖对象却未正确关联到被测类,会导致模拟失效(如userinfodto为null);根本原因在于混淆了spring容器管理与纯mockito测试的上下文机制。

当您在 @SpringBootTest 环境中混合使用 @ExtendWith(MockitoExtension.class) 时,需特别注意测试目标的定位:

  • @SpringBootTest 启动完整Spring上下文,适用于端到端或组件级集成测试,此时应优先使用 @MockBean(由Spring Test提供)替代原生 @Mock;
  • @ExtendWith(MockitoExtension.class) 是纯 Mockito 单元测试扩展,适用于无Spring容器的轻量级单元测试,此时应配合 @InjectMocks + @Mock 构建被测对象实例。

您当前代码的问题本质是:
✅ @Mock UserInfoDto userInfo 创建了一个Mock对象;
❌ 但 @Autowired UserRepository userRepository 从Spring容器注入的是真实Bean(其内部依赖的 UserInfoDto 并未被替换);
❌ userInfo 未被注入到 userRepository 中,因此调用链中实际使用的仍是 null 或默认构造实例。

✅ 正确做法取决于您的测试目标:

场景一:您想测试 UserRepository 的逻辑(且它依赖 UserInfoDto)——推荐纯单元测试(不启动Spring上下文):

// 移除 @SpringBootTest,改用纯 Mockito 测试@ExtendWith(MockitoExtension.class)class UserRepositoryTest {    @Mock    private UserInfoDto userInfoDto; // 模拟依赖    @InjectMocks    private UserRepository userRepository; // 自动将 @Mock 注入其中    @BeforeEach    void setUp() {        when(userInfoDto.getXCaller()).thenReturn("Test");    }    @Test    void testSomeMethod() {        // 执行测试逻辑        String result = userRepository.processUser();        assertThat(result).isEqualTo("Test");    }}

场景二:您必须在 Spring 上下文中测试(例如需数据库连接、事务等)——请改用 @MockBean:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)class IntegrationTest {    @Autowired    private UserRepository userRepository;    @MockBean // ✅ Spring-aware mock:自动替换容器中同类型Bean    private UserInfoDto userInfoDto;    @BeforeEach    void setUp() {        when(userInfoDto.getXCaller()).thenReturn("Test");    }    @Test    void testWithSpringContext() {        // userRepository 内部使用的 UserInfoDto 已被 @MockBean 替换        assertThat(userRepository.getCallerInfo()).isEqualTo("Test");    }}

⚠️ 关键注意事项:

  • ❌ 不要混用 @Mock(来自 Mockito)和 @Autowired(来自 Spring)在同一测试类中试图“手动注入”——Spring 不会识别 @Mock 对象;
  • ✅ @MockBean 是 Spring Boot Test 提供的专用注解,会动态注册/替换 Spring 容器中的 Bean,与 @SpringBootTest 天然兼容;
  • ✅ 若坚持使用 @ExtendWith(MockitoExtension.class),则必须放弃 @SpringBootTest,改用 @InjectMocks 显式组装被测对象;
  • @Mock 和 @InjectMocks 必须成对出现,且确保字段名或类型能被 Mockito 正确匹配(建议配合 @Mock(answer = Answers.RETURNS_DEEP_STUBS) 处理嵌套调用)。

总结:选择测试策略前,请明确目标——是验证 Spring 组件协作(用 @MockBean + @SpringBootTest),还是验证单个类逻辑(用 @Mock + @InjectMocks + @ExtendWith)。二者不可随意混搭,否则必然导致模拟失效与空指针异常。

热门栏目