Mockito使用withSettings().useConstructor()时参数匹配器无效错误如何解决
问题根因
- 依赖注入逻辑错误:业务代码直接在方法内部
new DataSourceTransactionManager(...)实例化事务管理器,你在测试类中Mock的PlatformTransactionManager对象完全不会被业务代码调用,Mock逻辑本身就不生效。 - 匹配器使用触发校验异常:你同时使用
@Mock注解声明platformTransactionManager,又手动通过Mockito.mock(DataSourceTransactionManager.class, withSettings().useConstructor(dataSource))覆盖该变量,创建带构造参数的Mock实例时传入的是原始Mock对象(非参数匹配器),后续调用getTransaction(any())时,Mockito全局栈存储的参数匹配器计数出现错位,触发了InvalidUseOfMatchersException异常。
解决方案
方案一:优化业务代码依赖注入(推荐)
调整业务代码,将事务管理器改为通过Spring注入的方式获取,避免硬编码实例化,从根源上解决Mock不生效的问题:
// 业务类通过构造函数注入事务管理器 private final PlatformTransactionManager transactionManager; public YourBizService(PlatformTransactionManager transactionManager) { this.transactionManager = transactionManager; } // 业务方法直接使用注入的实例 public void doBizOperate() { DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition(); TransactionStatus status = transactionManager.getTransaction(paramTransactionDefinition); // 后续业务逻辑 }
对应的测试代码可以简化为:
@Mock private PlatformTransactionManager platformTransactionManager; @Mock private TransactionStatus transactionStatus; // 自动将Mock的实例注入到业务类中 @InjectMocks private YourBizService yourBizService; // 仅需Stub对应的方法即可 given(platformTransactionManager.getTransaction(any(TransactionDefinition.class))).willReturn(transactionStatus);
方案二:不修改业务代码的兼容方案
如果暂时无法调整业务代码的硬编码逻辑,可以使用Mockito的构造方法Mock能力,直接拦截业务代码中new DataSourceTransactionManager的逻辑:
// 测试方法中添加构造Mock逻辑 try(MockedConstruction<DataSourceTransactionManager> mockedTxManager = Mockito.mockConstruction( DataSourceTransactionManager.class, (mock, context) -> given(mock.getTransaction(any(TransactionDefinition.class))).willReturn(transactionStatus) )) { // 执行业务测试逻辑 yourBizService.doBizOperate(); }
如果要保留你原有测试代码的写法,仅修复匹配器异常,需要做两处调整:
- 删除
@Mock private PlatformTransactionManager platformTransactionManager;注解声明,避免重复创建Mock实例 - 将
any()改为明确类型的any(TransactionDefinition.class),避免匹配器类型错位
内容的提问来源于stack exchange,提问作者mattsmith5
相关产品推荐
相关产品推荐

