使用@SpyBean模拟Environment方法时抛出NotAMockException的解决方法
解决@SpyBean模拟Environment方法抛出NotAMockException的问题
问题根因
这个错误的核心原因有两个:
Environment接口的acceptsProfiles(Profiles)是Java默认方法,传统Mockito依赖的CGLIB/ASM字节码工具无法直接模拟接口默认方法;@SpyBean注入的对象被Spring代理层包裹,Mockito无法识别它为标准的spy实例。
可行解决方案
方案1:引入Mockito-inline扩展(推荐)
Mockito-inline扩展支持模拟接口默认方法,只需添加依赖:
- Maven:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-inline</artifactId> <version>4.11.0</version> <!-- 使用最新稳定版即可 --> <scope>test</scope> </dependency>
- Gradle:
testImplementation 'org.mockito:mockito-inline:4.11.0'
添加依赖后,原代码只需调整参数匹配方式(避免触发真实方法):
@SpyBean private Environment environment; @Test void yourTestMethod() { // 用any()匹配Profiles参数,避免直接调用真实方法 doReturn(true).when(environment).acceptsProfiles(any(Profiles.class)); // 执行测试逻辑 }
方案2:手动创建Spy替换Spring Bean
如果不想加额外依赖,可手动将真实Environment包装为Spy并替换容器中的Bean:
@SpringBootTest class YourTestClass { @Autowired private ApplicationContext context; private Environment environmentSpy; @BeforeEach void setUp() { // 取出真实Environment并包装为Spy Environment realEnv = context.getBean(Environment.class); environmentSpy = Mockito.spy(realEnv); // 替换目标Bean中的Environment引用(假设测试的是YourService) YourService service = context.getBean(YourService.class); ReflectionTestUtils.setField(service, "environment", environmentSpy); } @Test void testAcceptsProfiles() { doReturn(true).when(environmentSpy).acceptsProfiles(Profiles.of("prod")); // 执行测试逻辑 } }
替代方案:直接用@MockBean(如果不需要真实行为)
如果你不需要保留Environment的真实方法逻辑,直接用@MockBean会更简单:
@MockBean private Environment environment; @Test void yourTestMethod() { when(environment.acceptsProfiles(Profiles.of("prod"))).thenReturn(true); // 测试逻辑 }
内容的提问来源于stack exchange,提问作者Greg
相关产品推荐
相关产品推荐

