使用PowerMock模拟单例的getInstance方法

3

我有一个单例模式,返回一个不同类的实例。我想要Mock返回的实例对象上的方法。我一直在阅读PowerMock关于最终类和单例模式的Mock特性,但我不知道我的情况是否属于这些范畴。感谢您的建议。

public final class SomeWrapper {
    private MyActualObject MyActualObject;
    private static final SomeWrapper instance = new SomeWrapper();

    private SomeWrapper() {
        // singleton
    }

    public static SomeWrapper getInstance() {
        return instance;
    }

    public void setMyActualObject(MyActualObject MyActualObject) {
        if(this.MyActualObject == null) {
            this.MyActualObject = MyActualObject;
        } else {
            throw new UnsupportedOperationException("MyActualObject is already set, cannot reset.");
        }
    }

    public MyActualObject getMyActualObject() {
        return MyActualObject;
    }
}

现在,在我的单元测试中,我想模拟以下行:

when(SomeWrapper.getInstance().getMyActualObject().isActive()).thenReturn(false);

我应该模拟SomeWrapper和MyActualObject吗?有什么示例代码可以作为指导吗?

2
你一开始就不应该使用Java的单例模式。(这并不意味着你的应用程序不应该有单例对象...)将单例类变成一个普通类,并添加一个公共构造函数。 - Timothy Truckle
2个回答

4

使用以下Mockito和PowerMock版本:

testImplementation 'org.mockito:mockito-core:2.23.4'
testImplementation 'org.powermock:powermock-module-junit4:2.0.0-beta.5'
testImplementation 'org.powermock:powermock-api-mockito2:2.0.0-beta.5'

你可以使用PowerMock.mockStatic()when()机制模拟一个AndroidMainApplication单例实例,例如:

private MainApplication mApplication;

@NonNull
protected MainApplication getApplication() {
    if (mApplication == null) {
        mApplication = PowerMockito.mock(MainApplication.class);

        PowerMockito.mockStatic(MainApplication.class);
        PowerMockito.when(MainApplication.getInstance()).thenReturn(mApplication);
        PowerMockito.when(mApplication.getBaseContext()).thenReturn(mApplication);
        PowerMockito.when(mApplication.getApplicationContext()).thenReturn(mApplication);
    }
    return mApplication;
}

模拟私有构造函数可能有点棘手 - 您可以尝试本帖子中建议的方法,通过在thenReturn()调用中使用替代类:

SO - 模拟私有构造函数

0
这里的重点是:你编写了难以测试的代码。是的,PowerMock可以帮助“修复”它,但你可能更喜欢重新设计你的生产代码,使其更易于测试。
例如,通过添加一个包保护构造函数,如下所示:
SomeWrapper(MyActualObject myActualObject) {
  this.MyActualObject = myActualObject;
}

这将允许您创建一个SomeWrapper类的实例,该实例接收完全有效的MyActualObject实例。

在这个意义上:你可能想学习如何创建实际可testable的产品代码。


1
我对你没意见,但这并没有回答问题。 - Alejandro González
1
你不应该假设原问题的作者编写了他正在询问的代码,也不应该假设他有能力对其进行更改。 - Fopedush

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