如何禁用Mockito生成的mock对象上继承的注解?
禁用Mock对象上继承的@Transactional注解的可行方案
以下方案按落地成本从低到高排序,可根据测试场景选择:
- 优先用纯Mock对象脱离Spring AOP管控
单元测试场景下不要把Mock对象交给Spring容器管理,直接用Mockito等框架生成原生Mock对象即可,这类对象不会经过Spring的Bean后置处理器,不会被事务切面拦截,自然不会触发开启事务的逻辑。
示例代码:// 直接生成原生mock,不要用@MockBean注入到Spring容器 BizService mockService = Mockito.mock(BizService.class); Mockito.when(mockService.doTxOperation()).thenReturn(testResult);
注意:如果用@MockBean注解把Mock对象注入Spring容器,对象会被容器的AOP逻辑扫描,依然会触发事务拦截。 - 集成测试场景直接关闭事务自动代理
如果必须加载Spring测试上下文跑集成测试,可以直接在测试类的配置里关闭事务自动代理创建,容器就不会为任何Bean生成事务代理:@SpringBootTest(properties = "spring.transaction.auto-proxy-creation=false")
也可以在测试配置类中直接排除TransactionInterceptor的Bean注册,从根源上移除事务拦截逻辑。 - 字节码抹除Mock类方法上的事务注解
如果需要保留Spring其他AOP能力,只需要去掉Mock对象方法上的@Transactional,可以用ByteBuddy动态生成子类时移除对应方法的注解,Spring扫描事务注解时会判定该方法不需要事务增强:Class<? extends BizService> mockClz = new ByteBuddy() .subclass(BizService.class) .method(ElementMatchers.named("doTxOperation")) .withoutAnnotations() // 清除目标方法上的所有注解,包括父类继承来的@Transactional .make() .load(BizService.class.getClassLoader()) .getLoaded(); BizService mockService = mockClz.getDeclaredConstructor().newInstance(); - 手动写测试桩覆写原事务方法
直接在测试代码中编写原类的子类,覆写带@Transactional的方法,不添加@Transactional注解即可。方法级注解本身不支持JDK层面的继承,Spring查找事务注解时如果子类方法有覆写,会优先读取子类方法上的注解,只要子类方法没标@Transactional就不会触发事务代理:// 测试内部类,直接new使用,不要交给Spring容器代理 static class TestBizService extends BizService { @Override public Result doTxOperation() { // 自定义测试桩逻辑 return testResult; } }
内容的提问来源于stack exchange,提问作者Veteran
相关产品推荐
相关产品推荐

