【问题标题】:How to mock both static and non static methods in a same class using powerMock?如何使用 powerMock 在同一个类中模拟静态和非静态方法?
【发布时间】:2014-07-01 16:20:58
【问题描述】:

我有一个简单的案例来说明一个更复杂的案例(哦,Legacy Code,我爱你吗,吟游诗人会以你的名义唱出美妙的歌曲)。

如下图一组类:

  • 实用程序类:
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: 没有可用的模拟最后一次调用 在 org.easymock.EasyMock.getControlForLastCall(EasyMock.java:560) 在 org.easymock.EasyMock.expect(EasyMock.java:538) 在 org.osef.test.BTest.setUp(BTest.java:25) ...

  • 我只需要测试最后的 A 类。
  • 我需要避免它的构造函数逻辑(在我对 doStuff 方法的测试中是怪异且无关紧要的)。
  • 我必须测试那个 doStuff。

知道如何有效地做我想做的事吗?

【问题讨论】:

    标签: java unit-testing easymock powermock


    【解决方案1】:

    我认为您的问题是您没有重播课程,您只是在每次测试中重播 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
    • 别担心!我最近一直在自己学习 PowerMock 的乐趣,所以我很想听听您最终确定您的问题是什么。
    • 我的问题只是我懒惰(/受项目限制)阅读整个文档(顺便说一句,我很难阅读而且不是很清晰和简洁)我猜。不管怎样,你是个救命恩人
    猜你喜欢
    • 2012-02-09
    • 2019-10-28
    • 2014-02-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-10
    • 1970-01-01
    相关资源
    最近更新 更多