Powermock 在最终无效方法上意外抛出 InvalidUseOfMatchersException

Powermock unexpectedly throwing InvalidUseOfMatchersException on final void method

我正在对我的 Java 应用程序进行单元测试..

我的目标是使用 Powermock 在 BOProcessor class 的实例上创建一个间谍。 BOProcessor 有一个 final void 方法;我将设置我的间谍在调用此方法时抛出异常。我也将在同一个测试中模拟 MyDao,但模拟这个 class 很简单。然后,模拟的 MyDao 将被传递到名为 classUnderTest 的 MyDaoService 实例中。然后我将针对 classUnderTest.

做出断言

每当我尝试设置上述场景时,Powermock(或 Mockito?)都会在我对间谍设置 doThrow 时抛出 InvalidUseOfMatchersException。奇怪的是,只有在 doThrow 期望之后调用 classUnderTest 时才会抛出此异常。如果我删除稍后调用 classUnderTest,则预期工作正常。甚至更奇怪 - classUnderTest 甚至不使用抛出错误的间谍!

这是我上面概述的全部测试代码。为了突出问题,我删除了所有不直接相关的代码。 (我什至删除了这个测试的全部目的。)

package my.package;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.doThrow;
import static org.powermock.api.mockito.PowerMockito.mock;
import static org.powermock.api.mockito.PowerMockito.spy;

import org.junit.Test;

public class WhatAmIDoingWrong {

    @Test
    public void whatAmIDoingWrong() {

        MyDao mockedDao = mock(MyDao.class);
        BOProcessor processor = new BOProcessor();
        BOProcessor mockedProcessor = spy(processor);

        MyDaoService classUnderTest = new MyDaoService(mockedDao);

        doThrow(new Exception()).when(mockedProcessor).process(any(FakeBusinessObject.class));

        classUnderTest.interactWithDao();
    }
}

这是异常 - 从我的测试代码的 doThrow 行抛出(具有讽刺意味的是) - 我正在尝试解决。

org.mockito.exceptions.misusing.InvalidUseOfMatchersException: 
Invalid use of argument matchers!
0 matchers expected, 1 recorded:
-> at my.package.WhatAmIDoingWrong.whatAmIDoingWrong(WhatAmIDoingWrong.java:21)

This exception may occur if matchers are combined with raw values:
    //incorrect:
    someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
    //correct:
    someMethod(anyObject(), eq("String by matcher"));

For more info see javadoc for Matchers class.

    at my.package.MyDaoService.interactWithDao(MyDaoService.java:33)
    at my.package.WhatAmIDoingWrong.whatAmIDoingWrong(WhatAmIDoingWrong.java:23)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    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.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
    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[=11=]0(ParentRunner.java:58)
    at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
    at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
    at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
    at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)

这是我的测试使用的 classes。重申一下,名为 classUnderTest 的 MyDaoService 甚至不知道 BOProcessor 的间谍;它只适用于 MyDao 的模拟。但是只有当 classUnderTest 被调用时,对 BOProcessor 间谍的期望才会失败。

public class BOProcessor {

    public final void process(FakeBusinessObject bar) {}
}
public class FakeBusinessObject {

}
import java.util.Collections;
import java.util.List;

public class MyDao {

    public MyDao() {}

    public List<String> getAllData(){
        return Collections.emptyList();
    }

}
public class MyDaoService {

    private MyDao applicationDao;

    public MyDaoService(MyDao applicationDao) {
        this.applicationDao = applicationDao;
    }

    public synchronized void interactWithDao() {
        applicationDao.getAllData();
    }
}

我使用的是 JUnit 4.12、Mockito 1.10.19 和 Powermock 1.7.4。该项目是 运行 Spring 4.3.12RELEASE,包含 spring-test。

为什么 Powermock 抛出这个异常?我没有正确使用 any 匹配器吗?为什么只有当 later 调用与 different mock 交互时才抛出此异常?

感谢您的帮助!

原来我用错了Spies。 org.mockito.stubbing.Stubber.when(T mock) 实施方式中的某些东西意味着我无法按照我想要的方式对间谍设定期望。但无论如何,Capture 实际上更适合我的用例。

最后,我的测试是这样的:

public class FixedNow{

    @Test
    public void fixedNow() {

        MyDao mockedDao = mock(MyDao.class);
        BOProcessor mockedProcessor = mock(BOProcessor.class);
        FakeBusinessObject problematicBO = new FakeBusinessObject();
        ArgumentCaptor<FakeBusinessObject> fakeBOCaptor = ArgumentCaptor.forClass(FakeBusinessObject.class);

        MyDaoService classUnderTest = new MyDaoService(mockedDao, mockedProcessor);

        doThrow(new Exception()).when(mockedProcessor).process(eq(problematicBO));
        doNothing().when(mockedProcessor).process(fakeBOCaptor.capture());

        classUnderTest.interactWithDao();

        assertThings(BOCaptor.getValue());
    }
}

感谢您的想法!