Spring Boot 2.4.1中@Spy与@Autowired结合引发NotAMockException问题求助
解决Mockito的NotAMockException异常问题
你遇到的这个org.mockito.exceptions.misusing.NotAMockException异常,核心原因是你把Spring容器管理的真实Repository对象直接用@Spy标记了——SimpleJpaRepository是Spring Data JPA生成的代理实例,不是Mockito创建的mock/spy对象,当openMocks(this)执行时,Mockito会尝试将这个Spring代理对象当作自己的mock来处理,自然就会报错。
下面给你两种可行的解决方案,优先推荐第一种:
方案1:使用Spring Boot提供的@SpyBean注解(推荐)
Spring Boot专门提供了@SpyBean注解,用来Spy Spring容器中已存在的Bean,完美解决Spring代理与Mockito的冲突。你只需要把原来的@Spy + @Autowired替换成@SpyBean即可:
@ExtendWith(SpringExtension.class) @SpringBootTest(classes = TestServer.class) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("test") @Transactional class SampleServiceTest { // 替换@Spy + @Autowired为@SpyBean @SpyBean private TestRepo repo; @Mock SpecialTest test; @Mock SpecialTest1 test1; // 注意:这里是@InjectMocks,不是@InjectMock(拼写错误) @InjectMocks TestServiceTest testService; @BeforeEach() void setup () { openMocks(this); // 注意:两次when同一个方法返回不同值,最后一次会覆盖前一次,按需调整 when(testService.getId()).thenReturn(test1); } @Test void test () { // 你的测试逻辑 } }
@SpyBean会自动从Spring容器中获取TestRepo的实例,创建对应的Spy对象后再放回容器,让Mockito和Spring能完美协作。
方案2:手动创建Spy对象(适合理解原理)
如果你不想用@SpyBean,也可以手动创建Spy实例并处理依赖注入:
@ExtendWith(SpringExtension.class) @SpringBootTest(classes = TestServer.class) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) @ActiveProfiles("test") @Transactional class SampleServiceTest { @Autowired private TestRepo realRepo; private TestRepo repoSpy; @Mock SpecialTest test; @Mock SpecialTest1 test1; @InjectMocks TestServiceTest testService; @BeforeEach() void setup () { openMocks(this); // 手动基于真实Repository创建Spy repoSpy = Mockito.spy(realRepo); // 把Spy对象注入到依赖它的Service中 ReflectionTestUtils.setField(testService, "repo", repoSpy); when(testService.getId()).thenReturn(test1); } @Test void test () { // 使用repoSpy执行测试逻辑 } }
这种方式需要手动处理依赖注入,比较繁琐,所以优先推荐方案1。
额外需要修正的小问题
@InjectMock拼写错误:你代码里写成了@InjectMock,正确注解是@InjectMocks,用来让Mockito自动注入Mock/Spy到目标实例。- 重复的
when设置:setup里两次给testService.getId()设置返回值,后一次会覆盖前一次,根据实际需求调整即可。 - 多个
@InjectMocks:同一个测试类给两个类标记@InjectMocks容易导致依赖混乱,建议一个测试类专注测试一个Service,拆分后逻辑更清晰。
内容的提问来源于stack exchange,提问作者user12639212
相关产品推荐
相关产品推荐

