我应该如何处理DI和测试的上下文对象?

时间:2017-09-20 13:10:38

标签: java android unit-testing android-studio android-context

我有一个创建位图对象的类。

它需要访问位图资源,因此需要访问我传递给构造函数的上下文,所以我称之为 myClass(context)

理想情况下,我想以某种方式注入依赖。我想用工厂做这个,所以我可以向工厂询问对象并为我创建它,但我只能从创建新窗口的活动类中获取上下文。因此,我似乎必须继续从主要活动中传递上下文。

我最近问了一个类似的问题,并被告知我根本不应该静态调用上下文,并且应该总是传递它。

这意味着如果我想测试这个类,我的测试类需要访问android框架(这意味着我无法在本地测试并且必须使用AndroidTests)。

它是如何工作的?我的类只需要一个位图,但由于上下文,我现在无法在本地测试。

2 个答案:

答案 0 :(得分:1)

如果您的班级只需要位图,为什么不能模拟位图?你应该测试你班上的逻辑。您不需要测试Context位图加载功能,因为我确信它已经在Android框架中进行了测试。您已经对工厂模式有了一个好主意,因为您可以在应用程序中使用myClass(bitmapFactory)并在测试中使用myClass(mockFactory)注入模拟工厂进行测试。

如果您完全确定需要编写测试来覆盖位图加载,那么请查看像robolectric这样的测试框架,因为它可以为这样的场景提供模拟上下文

答案 1 :(得分:1)

如果您需要Context的功能,那么您需要以某种方式将其传递给MyClass。但是,这并不意味着您需要静态存储Context。事实上,这将是一个非常糟糕的设计选择(看起来你已经知道了)。

如果您使用Dagger,那么我有this video教程,解释如何构建依赖注入代码。这种结构的一部分确实处理了Context对象的复杂性。

现在,即使MyClass需要访问Context才能获取位图,但这并不意味着您需要解决集成测试问题。

首先,您可以使用Robolectric - 这个库"模拟" Android框架,我认为它支持从资源中获取位图。

但是,根据您的使用情况,还有一个更简单的选项。您真的需要特定的位图,或者您只是想确保MyClass对此位图执行特定操作吗?

如果你需要你作为资源添加的特定的那个,那么去Robolectric,但如果没有,你需要的只是确保正确使用获得的位图,那么你可以只是模拟位图。

为了提高可读性,简化测试并防止违反Demeter法,我建议你将Context包装到这个类中:

public class BitmapRetriever {
    private final Context mContext;

    public BitmapRetriever(Context context) { 
        mContext = context;
    }

    public Bitmap getBitmapById(int id) {
        // code that obtains bitmap
    }
}

然后让MyClass取决于BitmapRetriever而不是Context

执行此操作后,可以直接在测试中传递模拟BitmapRetriever,当Bitmap要求时,将返回模拟MyClass。然后你可以在那个模拟上断言各种条件。