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

时间:2015-08-19 17:19:14

标签: java junit arguments mockito 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$1.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$3.run(ParentRunner.java:290)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
    at org.junit.runners.ParentRunner$2.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)

1 个答案:

答案 0 :(得分:2)

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

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

你拥有它的方式,调用argThat,然后调用verifyverify检查没有发生未使用的匹配器调用。这会触发您的例外。

相反,内联电话:

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

...或者改为使用方法调用,这样可以使订单保持正确:

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

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