4

我正在尝试对一些使用 Singleton 类的类进行单元测试,该类的构造函数做了一些我在单元测试环境中不能(也不应该)做的事情。我的理想方案是最终完全抑制构造函数,然后将我的测试类调用的其他成员方法排除在外。我的问题是我似乎无法抑制构造函数。

我对解决此问题的方法的理解如下:

public class MySingleton extends AbstractSingletonParent {
    public final static MySingleton Only = new MySingleton();
    private MySingleton(){
        super(someVar); // I want the super-class constructor to not be called
        //
        //more code I want to avoid
    }

    public Object stubbedMethod() {}
}

public class ClassToBeTested {
    public void SomeMethod(){
        Object o = MySingleton.Only.stubbedMethod();
    }
}


@RunWith(PowerMockRunner.class)
@PrepareForTest(MySingleton.class)
public class TestClass {
    @Test
    public void SomeTest() {
        suppress(constructor(MySingleton.class));
        mockStatic(MySingleton.class);

        PowerMock.replay(MySingleton.class);
        // invoke ClassToBeTested, etc

        PowerMock.verify(MySingleton.class);

        //make some assertions
    }
}

不幸的是,在 createMock 调用期间,MySingleton 构造函数被命中,它仍然调用超级构造函数。

我在做傻事吗?我在网上找到了一个几乎完全一样的例子,但它使用了不推荐使用的 suppressConstructor 方法。尽管被弃用,我也尝试过,但无济于事......

我正在尝试做的事情可能吗?如果是这样,我做错了什么?

*编辑版本现在可以使用。

4

3 回答 3

2

您需要使用注释TestClass进行@PrepareForTest注释,以便它有机会操纵单例的字节码。

此外,超类 ctor 抑制签名应包括somevar'class; 现在你只是在抑制默认的ctor。

请参阅@PrepareForTestAPI 文档。这是一篇包含更多详细信息的博客文章。

FWIW,它对我有用:

@RunWith(PowerMockRunner.class)
@PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {

    @Test
    public void testEvil() {
        suppress(constructor(EvilBase.class));
        assertEquals(69, EvilBase.getInstance().theMethod());
    }

    @Test public void testNice() {
        suppress(constructor(EvilBase.class));
        suppress(constructor(NicerSingleton.class));
        assertEquals(42, NicerSingleton.getInstance().theMethod());
    }

}
于 2011-11-11T22:49:46.337 回答
0

I am not sure what is it that you are doing wrong. But on the design side, i can suggest you look into dependency injection i.e. DI.

For making your code testable, make use of DI. With DI you would pass the singleton class as an constructor argument to your test class. And now since you pass an argument, inside your test case you can create a custom implementation of the AbstractSingleton class and your test case should work fine.

With DI, your code will become more testable.

于 2011-11-11T22:53:01.633 回答
0

您如何'only'使用您想要的构造函数实例化的实例设置 Singleton 的实例字段(在您的代码中)(您可以使用 Reflection API 或dp4j完成所有这些操作)。

dp4j 出版物的激励示例讨论了这一点。

于 2011-11-17T20:54:43.610 回答