PowerMock EasyMock基础知识

phe*_*aal 4 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);
}
Run Code Online (Sandbox Code Playgroud)

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

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

但我得到的错误是:

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)
Run Code Online (Sandbox Code Playgroud)

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

rru*_*fai 13

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

缺少电话

你似乎错过了一个调用方法PowerMock.mockStatic或其中一个PowerMock.mockPartialMock方法(另见这个).第一种方法将模拟传递给它的所有静态方法,而第二种方法将仅模拟它给出的方法列表.

一个例子

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

@RunWith(PowerMockRunner.class)
@PrepareForTest(Dummy.class)
public class DummyTest {
Run Code Online (Sandbox Code Playgroud)

第一个注释告诉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();
    }
Run Code Online (Sandbox Code Playgroud)

部分静态模拟

这是另一个测试,我们不会模拟所有方法,只模拟我们传递给的方法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);
    }
}
Run Code Online (Sandbox Code Playgroud)

让模拟类Dummy定义如下:

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

    public static boolean testOuter() {
        String x = "someValue";
        return testInner(x);
    }
}
Run Code Online (Sandbox Code Playgroud)

完全嘲笑与部分嘲讽

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

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

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

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