PowerMock EasyMock基础知识

时间:2012-01-26 18:28:24

标签: java junit easymock powermock

这可能是一个PowerMock / EasyMock 101问题,我无法弄清楚为什么。 我有一个带有方法的C类

public static boolean testInner(String s) {
    return false;
}

public static boolean testOuter() {
    String x = "someValue";
    return testInner(x);
}

在我的testOuter()方法测试中,我想确保使用适当的参数调用testInner。为此,我正在做这样的事情:[@ RunWith(PowerMockRunner.class) 在Class级别声明的@PrepareForTest(EmailUtil.class)

EasyMock.expect(C.testInner("blabla")).andReturn(true);
PowerMock.replayAll();
boolean status = C.testOuter();
PowerMock.verifyAll();  
assertTrue(status);

但我收到的错误是:

java.lang.AssertionError: 
Unexpected method call testOuter():
testInner("blabla"): expected: 1, actual: 0
    at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:45)
    at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:95)
    at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
    at org.powermock.core.MockGateway.methodCall(MockGateway.java:60)
    at C.testOuter(C.java)

我用EasyMock.IsA(String.class)替换了实际参数,但仍然没有运气。我很确定我在做一些从根本上说是愚蠢的事情。 有什么帮助吗?

3 个答案:

答案 0 :(得分:13)

我认为这里有两个问题,一个与测试代码中缺少调用有关。第二个问题与你对行为嘲弄的理解以及全部和部分嘲弄之间的区别有关。

缺少电话

您似乎错过了对PowerMock.mockStatic或其中一种PowerMock.mockPartialMock方法的调用(另请参阅this)。第一种方法将模拟传递给它的所有静态方法,而第二种方法将仅模拟它给出的方法列表。

示例

这是一个完整的示例,其中包含两个测试方法,说明了这两个选项。首先,我们必须使用这两个注释来注释测试类:

@RunWith(PowerMockRunner.class)
@PrepareForTest(Dummy.class)
public class DummyTest {

第一个注释告诉JUnit使用PowerMockRunner运行测试。第二个注释告诉PowerMock准备模拟Dummy类。

全静态模拟

接下来,我们将看一个示例,其中模拟了类Dummy中的所有静态方法。这是什么意思?这基本上意味着我们想用假的(模拟)替换实际的实现。这个假实现应该如何表现?这是我们在期望中指定的内容。

因此,在testStaticMock方法中,我们告诉EasyMock给我们两个方法的假实现。我们希望假Dummy.testOuter只返回true。我们会喜欢假的Dummy.testInner在传递参数true时返回"bb"。请注意,当这些模拟被激活(PowerMock.replayAll)时,测试代码将只运行假方法而不是实际实现 - 这似乎是您混淆的根源。我稍后会对此发表更多意见。

    @Test
    public void testStaticMock() {
        mockStatic(Dummy.class);
        EasyMock.expect(Dummy.testOuter()).andReturn(true);
        EasyMock.expect(Dummy.testInner("bb")).andReturn(true);
        replayAll();
        boolean status = Dummy.testOuter();
        Assert.assertTrue(status);
        status = Dummy.testInner("bb");
        Assert.assertTrue(status);
        verifyAll();
    }

部分静态模拟

这是另一个测试,我们不会模拟所有方法,只有我们传递给mockStaticPartial的方法。下面,我们告诉PowerMock我们只想模拟方法Dummy.testInner。因此,Dummy的一部分被嘲笑,其余部分被测试。

    @Test
    public void testPartialStaticMock() {
        mockStaticPartial(Dummy.class, "testInner");
        EasyMock.expect(Dummy.testInner("someValue")).andReturn(true);
        replayAll();
        boolean status = Dummy.testOuter();
        verifyAll();
        Assert.assertTrue(status);
    }
}

让被模拟的类Dummy定义如下:

public class Dummy {
    public static boolean testInner(String s) {
        return false;
    }

    public static boolean testOuter() {
        String x = "someValue";
        return testInner(x);
    }
}

完全模拟与部分模拟

了解完全静态模拟的一件事是所有静态方法都被模拟。因此,方法testOuter将被模拟版本替换,将具有如下实现:

    public static boolean testOuter() {
        return true; //or whatever value is provided in the expectation
    }

因此,我们不应期望模拟版本调用实际实现的方法。我们不想关心该方法的内部。这就是原因,我们决定无论如何都要嘲笑它 - 用玩具实现取代它的内部结构,只能按照我们为它设定的期望来定义。

另一方面,当我们进行部分模拟时,我们没有模拟testOuter,所以我们正在调用它的实际实现。

答案 1 :(得分:1)

你只是告诉EasyMock期望调用testInner(),而不是testOuter()。

 Unexpected method call testOuter():

试过这个:

EasyMock.expect(C.testInner("blabla")).andReturn(true);
EasyMock.expect(C.testOuter());
PowerMock.replayAll();

答案 2 :(得分:0)

响应提供使用mockStaticPartial()模拟静态void函数的示例调用流程。

PowerMock.mockStaticPartial(Sample.class, "test");
Sample.test();
EasyMock.expectLastCall();
PowerMock.replay(Sample.class);

稍后在测试中,如果你打电话:

assertFalse(Sample.returnFalseBool());

测试将调用实际方法,因为在这种情况下只模拟了test()函数。

免责声明:我知道这可能不是添加此答案的最佳位置,但是将各种相关问题的其他几个答案拼凑在一起帮我提出了这个答案,认为有必要把它放在某个地方。