如何在不使用@SpyBean注解的情况下以编程方式创建指定类的Mockito SpyBean?
如何在不使用@SpyBean注解的情况下以编程方式创建指定类的Mockito SpyBean?
嘿,这个需求我太懂了——不想让业务代码或者测试使用者手动加@SpyBean注解,想悄悄在底层搞定SpyBean的创建对吧?没问题,咱们直接用Mockito和Spring的上下文机制就能实现,给你两种实用的方法:
方法一:通过测试配置类注册SpyBean
这种方法适合需要在多个测试类中复用Spy的场景,咱们写个专门的测试配置类,把SpyBean注册到Spring上下文里:
import org.mockito.Mockito; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; @TestConfiguration public class SpyBeanAutoConfig { // 这里的Bean名称要和目标类的默认Bean名称一致(通常是类名首字母小写) @Bean public YourTargetClass yourTargetClass() { // 如果目标类有构造参数,可以先注入依赖再创建Spy // 比如:return Mockito.spy(new YourTargetClass(dependencyBean)); // 简单场景下直接创建Spy实例 return Mockito.spy(new YourTargetClass()); // 如果想Spy Spring已经管理的原始Bean,也可以这么写: // return Mockito.spy(applicationContext.getBean(YourTargetClass.class)); } }
然后在你的测试类里,用@Import(SpyBeanAutoConfig.class)把这个配置引入,Spring就会自动用这个Spy实例替换掉原来的YourTargetClass Bean,业务代码或者测试类里直接注入就能用啦。
方法二:在测试代码中动态替换Bean
如果只是某个测试方法需要用到Spy,不想写额外的配置类,咱们可以直接在测试里操作Spring上下文,动态替换Bean:
import org.mockito.Mockito; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.context.ConfigurableApplicationContext; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest public class YourBusinessTest { @Autowired private ConfigurableApplicationContext appContext; @Autowired private YourService yourService; // 这个类依赖了YourTargetClass private YourTargetClass targetSpy; @BeforeEach void setUp() { // 1. 获取上下文里的原始目标Bean YourTargetClass originalBean = appContext.getBean(YourTargetClass.class); // 2. 创建Spy实例 targetSpy = Mockito.spy(originalBean); // 3. 替换上下文里的Bean BeanDefinitionRegistry registry = (BeanDefinitionRegistry) appContext.getBeanFactory(); registry.removeBeanDefinition("yourTargetClass"); appContext.getBeanFactory().registerSingleton("yourTargetClass", targetSpy); } @Test void testBusinessLogic() { // 执行业务方法 yourService.doBusiness(); // 验证Spy的方法调用 Mockito.verify(targetSpy).targetMethod(); } }
注意:如果目标类是Spring代理类(比如带@Transactional、@Async注解),直接Spy原始实例可能会导致代理失效,这时候一定要先获取Spring上下文里的代理实例再创建Spy哦。
备注:内容来源于stack exchange,提问作者Marian Klühspies
相关产品推荐
相关产品推荐

