@InjectMocks注入新实例而非指定Mock的问题排查
问题原因与解决方案
核心问题
你遇到的问题是**@SpringBootTest与Mockito的@InjectMocks注解冲突**,导致Spring上下文覆盖了Mockito的依赖注入逻辑。
具体原因
- @SpringBootTest启动Spring上下文:这个注解会加载Spring容器,自动扫描并创建带有@Repository注解的Bean(这里是SomeRepository的Spring Data代理实例),而非你用@Mock定义的Mockito Mock实例。
- Spring依赖注入优先级更高:当Spring上下文存在时,Service中的
someRepository会被Spring容器中的Bean替换,而不是Mockito通过@InjectMocks注入的Mock。你的Mapper能正常注入是因为你在@SpringBootTest的classes参数中指定了SomeMapperImpl,且它不是Spring Data自动生成的代理类型,Spring没有创建新的Bean覆盖你的Spy实例。 - 手动注入能工作的原因:直接通过
new SomeService(someRepository, someMapper)创建Service时,完全绕过了Spring的依赖注入逻辑,直接使用你定义的Mock和Spy实例,因此不会被替换。
解决方案
方案一:纯Mockito单元测试(推荐,更快更轻量)
移除@SpringBootTest和SpringExtension,只使用Mockito的注解,不需要启动Spring上下文:
@ExtendWith(MockitoExtension.class) class SomeServiceTest { @Mock private SomeRepository someRepository; @Spy private SomeMapperImpl someMapper; @InjectMocks private SomeServiceImpl someService; @Test void testGetVorgangById_ValidId() { SomeClass someObject = new SomeClass(); // 初始化测试用实体 when(this.someRepository.findById(1L)).thenReturn(Optional.of(someObject)); SomeDTO someById = this.someService.getById(1L); // 执行断言逻辑 } }
方案二:保留Spring上下文的测试(适用于需要Spring特性的场景)
改用Spring的@MockBean和@SpyBean注解,让Spring容器替换对应的Bean为Mock/Spy实例,通过@Autowired注入Service:
@SpringBootTest(classes = {SomeMapperImpl.class, OtherMapperImpl.class}) class SomeServiceTest { @MockBean private SomeRepository someRepository; @SpyBean private SomeMapperImpl someMapper; @Autowired private SomeServiceImpl someService; @Test void testGetVorgangById_ValidId() { SomeClass someObject = new SomeClass(); when(this.someRepository.findById(1L)).thenReturn(Optional.of(someObject)); SomeDTO someById = this.someService.getById(1L); // 执行断言逻辑 } }
内容的提问来源于stack exchange,提问作者D051P0
相关产品推荐
相关产品推荐

