5

这可能是 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) @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) 替换了实际参数,但仍然没有运气。我很确定我在这里做的事情基本上很愚蠢。有什么帮助吗?

4

3 回答 3

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.testInnertrue在传递参数时返回"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,所以我们调用了它的实际实现。

于 2012-08-05T01:44:17.770 回答
1

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

 Unexpected method call testOuter():

试过这个:

EasyMock.expect(C.testInner("blabla")).andReturn(true);
EasyMock.expect(C.testOuter());
PowerMock.replayAll();
于 2012-01-26T19:32:02.607 回答
0

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

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

稍后在测试中,如果您调用以下内容:

assertFalse(Sample.returnFalseBool());

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

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

于 2018-05-17T15:57:43.587 回答