在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) 时,需特别注意测试目标的定位:
您当前代码的问题本质是:
✅ @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"); }}
⚠️ 关键注意事项:
总结:选择测试策略前,请明确目标——是验证 Spring 组件协作(用 @MockBean + @SpringBootTest),还是验证单个类逻辑(用 @Mock + @InjectMocks + @ExtendWith)。二者不可随意混搭,否则必然导致模拟失效与空指针异常。