Java Mockito useConstructor withSettings,错误无效使用参数匹配器
Java Mockito useConstructor withSettings, error Invalid use of argument matchers
我正在尝试使用事务管理器模拟以下代码。接收错误如下。我该如何解决?
代码:
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource());
TransactionStatus status = transactionManager.getTransaction(paramTransactionDefinition);
测试:
@Mock
private JdbcTemplate jdbcTemplate;
@Mock
private PlatformTransactionManager platformTransactionManager;
@Mock
private DataSource dataSource;
@Mock
private TransactionStatus transactionStatus;
given(namedParameterJdbcTemplate.getJdbcTemplate()).willAnswer(a -> jdbcTemplate);
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
platformTransactionManager = Mockito.mock(DataSourceTransactionManager.class, withSettings().useConstructor(dataSource));
given(platformTransactionManager.getTransaction(any())).willAnswer(a -> transactionStatus);
错误:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at given(platformTransactionManager.getTransaction(any())).willAnswer(a -> transactionStatus);
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
正在尝试使用此资源:
我觉得你在嘲笑的时候有点太急切了。
给出的应该是这样的:
//method with parameter
given(aMock.aSingleCall(anArgumentMatcher)).willReturn(aValue);
//method without parameter
given(aMock.aSingleCall()).willReturn(aValue);
您在此处使用的链式调用:
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
应该分成两部分,像这样:
given(namedParameterJdbcTemplate.getJdbcTemplate()).willReturn(jdbcTemplate);
given(jdbcTemplate.getDataSource()).willReturn(dataSource);
在构造函数调用中,您遇到了存根时未实际使用模拟的问题。 Mockito 将无法用模拟神奇地替换您的构造函数调用(也不应该)。您应该简单地使用类似以下场景之一的东西。
A) 如果你只想模拟 dataSource
更改您的代码,您可以像这样设置 dataSource
模拟:
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
可以通过构造函数,也可以setter,无所谓。
B) 如果你也想模拟 transactionManager
更改您的代码以避免直接调用构造函数,接受 transactionManager
作为依赖项并设置您已经创建的模拟(名为 platformTransactionManager
的字段)。
注意:调用any(aClass)
将return执行any(aClass)
时类型的默认值。在你的例子中,这是一个 null
所以当你用它调用真正的构造函数时,你只是在写 new DataSourceTransactionManager(null)
额外的步骤。
更新#1:如何“以某种方式更改您的代码”?
这取决于您的其余代码,但假设这是在单个方法中:
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource());
TransactionStatus status = transactionManager.getTransaction(paramTransactionDefinition);
您可以使用 PlatformTransactionManager transactionManager
的参数并避免调用构造函数(提取参数),或者您至少可以提取对方法的构造函数调用,然后可以使用 Mockito 间谍来制作该方法 return 模拟而不是真实对象。
这会起作用:
@Mock
private JdbcTemplate jdbcTemplate;
@Mock
private PlatformTransactionManager platformTransactionManager;
@Mock
private DataSource dataSource;
@Mock
private TransactionStatus transactionStatus;
given(namedParameterJdbcTemplate.getJdbcTemplate()).willAnswer(a -> jdbcTemplate);
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
MockedConstruction<DataSourceTransactionManager> mocked = Mockito.mockConstruction(DataSourceTransactionManager.class,
(mock, context) -> {
when(mock.getTransaction(any())).thenReturn(null);
});
given(platformTransactionManager.getTransaction(new DefaultTransactionDefinition())).willAnswer(a -> transactionStatus);
mocked.close();
资源: https://rieckpil.de/mock-java-constructors-and-their-object-creation-with-mockito/
我正在尝试使用事务管理器模拟以下代码。接收错误如下。我该如何解决?
代码:
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource());
TransactionStatus status = transactionManager.getTransaction(paramTransactionDefinition);
测试:
@Mock
private JdbcTemplate jdbcTemplate;
@Mock
private PlatformTransactionManager platformTransactionManager;
@Mock
private DataSource dataSource;
@Mock
private TransactionStatus transactionStatus;
given(namedParameterJdbcTemplate.getJdbcTemplate()).willAnswer(a -> jdbcTemplate);
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
platformTransactionManager = Mockito.mock(DataSourceTransactionManager.class, withSettings().useConstructor(dataSource));
given(platformTransactionManager.getTransaction(any())).willAnswer(a -> transactionStatus);
错误:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at given(platformTransactionManager.getTransaction(any())).willAnswer(a -> transactionStatus);
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
正在尝试使用此资源:
我觉得你在嘲笑的时候有点太急切了。 给出的应该是这样的:
//method with parameter
given(aMock.aSingleCall(anArgumentMatcher)).willReturn(aValue);
//method without parameter
given(aMock.aSingleCall()).willReturn(aValue);
您在此处使用的链式调用:
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
应该分成两部分,像这样:
given(namedParameterJdbcTemplate.getJdbcTemplate()).willReturn(jdbcTemplate);
given(jdbcTemplate.getDataSource()).willReturn(dataSource);
在构造函数调用中,您遇到了存根时未实际使用模拟的问题。 Mockito 将无法用模拟神奇地替换您的构造函数调用(也不应该)。您应该简单地使用类似以下场景之一的东西。
A) 如果你只想模拟 dataSource
更改您的代码,您可以像这样设置 dataSource
模拟:
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(dataSource);
可以通过构造函数,也可以setter,无所谓。
B) 如果你也想模拟 transactionManager
更改您的代码以避免直接调用构造函数,接受 transactionManager
作为依赖项并设置您已经创建的模拟(名为 platformTransactionManager
的字段)。
注意:调用any(aClass)
将return执行any(aClass)
时类型的默认值。在你的例子中,这是一个 null
所以当你用它调用真正的构造函数时,你只是在写 new DataSourceTransactionManager(null)
额外的步骤。
更新#1:如何“以某种方式更改您的代码”?
这取决于您的其余代码,但假设这是在单个方法中:
DefaultTransactionDefinition paramTransactionDefinition = new DefaultTransactionDefinition();
PlatformTransactionManager transactionManager = new DataSourceTransactionManager(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource());
TransactionStatus status = transactionManager.getTransaction(paramTransactionDefinition);
您可以使用 PlatformTransactionManager transactionManager
的参数并避免调用构造函数(提取参数),或者您至少可以提取对方法的构造函数调用,然后可以使用 Mockito 间谍来制作该方法 return 模拟而不是真实对象。
这会起作用:
@Mock
private JdbcTemplate jdbcTemplate;
@Mock
private PlatformTransactionManager platformTransactionManager;
@Mock
private DataSource dataSource;
@Mock
private TransactionStatus transactionStatus;
given(namedParameterJdbcTemplate.getJdbcTemplate()).willAnswer(a -> jdbcTemplate);
given(namedParameterJdbcTemplate.getJdbcTemplate().getDataSource()).willAnswer(a -> dataSource);
MockedConstruction<DataSourceTransactionManager> mocked = Mockito.mockConstruction(DataSourceTransactionManager.class,
(mock, context) -> {
when(mock.getTransaction(any())).thenReturn(null);
});
given(platformTransactionManager.getTransaction(new DefaultTransactionDefinition())).willAnswer(a -> transactionStatus);
mocked.close();
资源: https://rieckpil.de/mock-java-constructors-and-their-object-creation-with-mockito/