如何使用PowerMock在同一类中模拟静态和非静态方法?

6

我是一个有用的助手,可以为您翻译文本。

我有一个简单的案例来说明一个更加复杂的案例(哦,遗留代码,我爱你,应该让吟游诗人唱出你的奇妙之名)。

想象一组类如下:

  • 实用类:
package org.osef.test;

public final class A {

    private static A instance;
    public static String status;

    private A() {
        initPaths();
    }

    public static A getInstance(){
            if(instance==null){
                instance = new A();
            }
            return instance;
    }

    private void initPaths() {
        A.status = "I have been in the method !";
    }
    public String doStuff() {
        return "stuff done ...";
    }
}
  • 调用它的类
package org.osef.test;

public class B {

    public String doBdo() {
        A instance = A.getInstance();
        return instance.doStuff();
    }
}
  • 测试这堆垃圾代码的类...咳咳...非常困难的“逻辑”。

包 org.osef.test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import org.easymock.EasyMock;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.reflect.Whitebox;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ A.class })
public class BTest {

    @Before
    public void setUp() {
        PowerMock.replace(PowerMock.method(A.class, "getInstance")).with(PowerMock.method(BTest.class, "giveOutInstance"));

        A a = A.getInstance();

        EasyMock.expect(a.doStuff()).andReturn("lol");
        EasyMock.replay(a);
    }

    @Test
    public void testDoBdo() {

        B b = new B();
        assertEquals("lol", b.doBdo());
        assertNull(A.status);
    }

    public static A giveOutInstance(){
        return Whitebox.newInstance(A.class);
    }
}

另一个方法是按以下方式进行:
  • 另一个方法已经是按以下方式进行:
package org.osef.test;

//[imports ommited here but are the same that those of the previous example]

@RunWith(PowerMockRunner.class)
@PrepareForTest({ A.class })
public class BTest {

    @Before
    public void setUp() {
        PowerMock.mockStatic(A.class);
        A a = Whitebox.newInstance(A.class);
        EasyMock.expect(A.getInstance()).andReturn(a);
        PowerMock.replay(A.class);

        EasyMock.expect(a.doStuff()).andReturn("lol");

        EasyMock.replay(a);
    }

    @Test
    public void testDoBdo() {

        B b = new B();
        assertEquals("lol", b.doBdo());
        assertNull(A.status);
    }

}

但是在所有情况下,我都会得到以下结果:

java.lang.IllegalStateException: no last call on a mock available at org.easymock.EasyMock.getControlForLastCall(EasyMock.java:560) at org.easymock.EasyMock.expect(EasyMock.java:538) at org.osef.test.BTest.setUp(BTest.java:25) ...

  • 我只需要测试最终的类A。
  • 我需要避免它的构造逻辑(在我的“doStuff”方法测试中非常庞大且不相关)。
  • 我必须测试“doStuff”。

有什么好的方法可以有效地做到我想做的吗?

1个回答

5
我觉得你的问题在于,你没有重播类,而是在每个测试中只重播A的模拟实例。 PowerMock.replayAll() 对你来说是很有用的。它将强制你对期望的类进入重放模式,然后你的模拟实例可以通过调用静态方法返回。
以下是我根据你的示例所创建的样本测试:
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class BTest{

    @Test
    public void thatCallingClassMakesExpectedCalls() {
        final A mockA = PowerMock.createMock(A.class);
        EasyMock.expect(mockA.doStuff()).andReturn("lol").anyTimes();

        PowerMock.mockStatic(A.class);
        EasyMock.expect(A.getInstance()).andReturn(mockA).anyTimes();

        PowerMock.replayAll(mockA);

        final B callingClass = new B();
        final String doBdo = callingClass.doBdo();
        assertThat(doBdo, is("lol"));

        EasyMock.verify(mockA);
        PowerMock.verifyAll();
    }
}

非常感谢!这个很好用,现在我会尝试弄清楚它为什么能够工作,我将深入文档进行研究,但是多亏了你,我知道该往哪个方向寻找:D - Ar3s
没问题!我最近也在学习PowerMock的乐趣,所以我很想知道你最终确定的问题是什么。 - Dan Temple
我的问题只是因为我太懒(或者受到项目限制的催促)而没有仔细阅读整个文档(顺便说一下,这个文档相当难以阅读,也不够清晰简明)。不管怎样,你真是我的救星。 - Ar3s

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接