首页 > 解决方案 > Java - 用于多个测试的模拟私有静态构造函数

问题描述

我是java测试的新手,现在一直在摆弄这个,没有运气,我有以下类:

public class Bar {
    public Object doSomething(int a, String b){
        return "something";
    }

    public Object doSomethingElse(int a, int b, String c){
        return "something else";
    }
}
public class Foo {
    private static Bar bar = new Bar();

    public static void start(int a, int b, String c){
        if(a == 1) { // some calculated condition
            bar.doSomething(a, c);
        } else {
            bar.doSomethingElse(a, b, c);
        }
    }
}
@RunWith(PowerMockRunner.class)
@PrepareForTest(Foo.class)
public class FooTest {
    @Test
    public void somethingTest() throws Exception {
        Bar barMock = createMock(Bar.class);

        expectNew(Bar.class).andReturn(barMock);

        expect(barMock.doSomething(1, "xxx")).andReturn("ABC");

        replay(barMock, Bar.class);

        Foo.start(1, 2, "xxx");
        verify(barMock, Bar.class);
    }

    @Test
    public void somethingElseTest() throws Exception {
        Bar barMock = createMock(Bar.class);

        expectNew(Bar.class).andReturn(barMock);

        expect(barMock.doSomethingElse(0, 2,"xxx")).andReturn("ABC");

        replay(barMock, Bar.class);

        Foo.start(0, 2, "xxx");
        verify(barMock, Bar.class);
    }
}

单独运行测试,但不是整个班级,我认为这与:

 private static Bar bar = new Bar();

但我不是 100% 确定。无论哪种方式,假设我无法更改 foo / bar 类,我该如何解决这个问题?

标签: javajunitmockitopowermockitoeasymock

解决方案


您面临的问题是 a 的static字段class仅初始化一次。因此第一个测试创建了一个新Bar对象,但是这个模拟在所有其他测试中都存在,因为没有触发新的创建。

相反,您应该使用为每个测试Reflections设置private static字段。PowerMock为您提供了一个名为Whitebox.

另请注意,只有在该类中setInternalState只有一个对象实例时才有效。Bar如果有多个,您将需要依赖普通的 Java 反射类。

示例见下:

@RunWith(PowerMockRunner.class)
@SuppressStaticInitializationFor("test.Foo") // optional, only required if the Bar class could not be created normally.
public class StaticTest {

    @Test
    public void somethingTest() throws Exception {
        Bar barMock = createMock(Bar.class);
        Whitebox.setInternalState(Foo.class, barMock);

        expect(barMock.doSomething(1, "xxx")).andReturn("ABC");

        replay(barMock, Bar.class);

        Foo.start(1, 2, "xxx");
        verify(barMock, Bar.class);
    }

    @Test
    public void somethingElseTest() throws Exception {
        Bar barMock = createMock(Bar.class);
        Whitebox.setInternalState(Foo.class, barMock);

        expect(barMock.doSomethingElse(0, 2,"xxx")).andReturn("ABC");

        replay(barMock, Bar.class);

        Foo.start(0, 2, "xxx");
        verify(barMock, Bar.class);
    }
}

我将它与静态初始化的抑制结合起来,但严格来说,这对您的测试来说不是必需的,因为Bar无论如何创建类都会成功。

Bar只有在无法创建类的情况下才应使用注释。请注意,您需要在此处输入包括包名称在内的完全限定名称(我假设包是test)。


推荐阅读