org.mockito.exceptions.misusing.InvalidUseOfMatchersException 尝试创建自定义参数匹配器时

org.mockito.exceptions.misusing.InvalidUseOfMatchersException when trying to create custom argument matcher

我正在使用 Mockito 1.10.18。我正在尝试为具有以下签名的方法创建自定义参数匹配器……

SaveResult[] com.sforce.soap.enterprise.EnterpriseConnection.update(SObject[] sObjects) throws ConnectionException

我编写了以下自定义参数匹配器……

class AccountMatcher extends ArgumentMatcher<SObject[]> 
{
    private Set<String> idList = new HashSet<String>();
    AccountMatcher(final Set<Account> mainList)
    {
        for (final Account acct : mainList)
        {
            idList.add(acct.getId());
        }   // for
    }   

    public boolean matches(Object param) 
    {
        final SObject[] compSet = ((SObject[]) param);
        final Set<String> compIdList = new HashSet<String>();
        for (final SObject acct : compSet)
        {
            compIdList.add(acct.getId());
        }   // for
        return Util.twoSetsMatch(compIdList, idList);
    }   // matches
 }

但是,当我尝试在我的 JUnit 测试中进行设置时……

    final Set<Account> firstBatch = new HashSet<Account>();
    firstBatch.add(acct);
    final SObject[] firstBatchAccts = Matchers.argThat(new AccountMatcher(firstBatch));
    Mockito.verify(mockConnection, Mockito.times(1)).update(firstBatchAccts);

当我 运行 它时,我得到以下异常……

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Misplaced argument matcher detected here:

-> at org.mainco.subco.sf.repo.AccountDaoIT.testUpdateAccountMaxRowsReached(AccountDaoIT.java:129)

You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
    when(mock.get(anyInt())).thenReturn(null);
    doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
    verify(mock).someMethod(contains("foo"))

Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
Mocking methods declared on non-public parent classes is not supported.

    at org.mainco.subco.sf.repo.AccountDaoIT.testUpdateAccountMaxRowsReached(AccountDaoIT.java:130)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.junit.runners.model.FrameworkMethod.runReflectiveCall(FrameworkMethod.java:50)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
    at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
    at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
    at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access[=14=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
    at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

这是因为您已经将 firstBatchAccts(Matcher 调用的结果)提取到一个变量,而不是一个方法。 argThat 和所有其他 Mockito 匹配器 work via side-effects,因此必须在正确的时间调用它们。

verify 检查一个空的匹配器堆栈,然后重置模拟的期望,这样它们就不会干扰验证。发生了一些匹配器调用,然后对要验证的方法的调用完成了该过程:它清除堆栈,检查发生的方法调用,并将模拟切换回存根行为(如果有)。

按照你的方式,argThat 被调用,然后调用 verifyverify 检查没有发生未使用的 Matcher 调用。这会触发您的异常。

改为内联调用:

verify(mockConnection).update(argThat(new AccountMatcher(firstBatch)));

...或者将其改为方法调用,以保持顺序正确:

public SObject[] arrayMatchingAccounts(Set<Account> accountSet) {
  return argThat(new AccountMatcher(accountSet));
}

verify(mockConnection).update(arrayMatchingAccounts(firstBatch));