我应该如何解决 DI 和测试的上下文对象?
How should I work around the context object for DI and testing?
我有一个 class 创建位图对象。
它需要访问位图资源,所以它需要访问我传递给它的构造函数的上下文,所以我这样称呼它 myClass(context)
理想情况下,我想以某种方式注入依赖项。我想用工厂来做这件事,所以我可以向工厂询问对象,它会为我创建它,但我只能从 activity classes 获取上下文,它创建了新的 windows.所以看来我必须继续从我的主要 activity.
传递上下文
我最近问了一个类似的问题,被告知我根本不应该静态调用上下文,应该始终传递它。
这意味着如果我想测试这个 class 我的测试 class 需要访问 android 框架(这意味着我不能在本地测试并且必须使用 AndroidTests ).
这是它应该的工作方式吗?我的 class 只需要一个位图,但由于上下文,我现在无法在本地进行测试。
如果您的 class 只需要位图,为什么您不能 mock 位图?您应该测试 class 中的逻辑。您不需要测试 Context
位图加载功能,因为我确信它已经在 Android 框架中进行了测试。您已经对 工厂模式 有了一个好主意,因为您可以通过在您的应用程序中使用 myClass(bitmapFactory)
并在您的测试中使用 myClass(mockFactory)
来注入一个模拟工厂进行测试。
如果您完全确定需要编写一个测试来涵盖位图加载,那么请研究像 robolectric 这样的测试框架,因为它可以提供 模拟上下文 对于这样的场景。
如果您需要 Context
的功能,则需要以某种方式将其传递给 MyClass
。但是,这并不意味着您需要静态存储 Context
。事实上,那将是一个非常糟糕的设计选择(看起来你已经知道了)。
如果您使用 Dagger,那么我有 this video 教程解释了如何构建依赖注入代码。这种结构的一部分确实是在处理 Context
个对象的复杂性。
现在,即使 MyClass
需要访问 Context
才能获取位图,这并不一定意味着您需要解析集成测试。
首先,你可以使用Robolectric - 这个库"mocks" Android 框架,我认为它支持从资源中获取位图。
但是,根据您的用例,还有一个更简单的选项。您真的需要特定的位图,还是只想确保 MyClass
对该位图执行特定的操作?
如果您需要作为资源添加的特定位图,请选择 Robolectric,但如果不需要,您需要的只是确保正确使用所获得的位图,然后您可以模拟位图。
为了增加可读性,简化测试,防止违反得墨忒耳法则,我建议你把Context
换成这个class:
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
.
一旦你这样做了,在 return 模拟 Bitmap
的测试中通过模拟 BitmapRetriever
将很简单当 MyClass
要求它时。然后你可以在那个模拟上断言各种条件。
我有一个 class 创建位图对象。
它需要访问位图资源,所以它需要访问我传递给它的构造函数的上下文,所以我这样称呼它 myClass(context)
理想情况下,我想以某种方式注入依赖项。我想用工厂来做这件事,所以我可以向工厂询问对象,它会为我创建它,但我只能从 activity classes 获取上下文,它创建了新的 windows.所以看来我必须继续从我的主要 activity.
传递上下文我最近问了一个类似的问题,被告知我根本不应该静态调用上下文,应该始终传递它。
这意味着如果我想测试这个 class 我的测试 class 需要访问 android 框架(这意味着我不能在本地测试并且必须使用 AndroidTests ).
这是它应该的工作方式吗?我的 class 只需要一个位图,但由于上下文,我现在无法在本地进行测试。
如果您的 class 只需要位图,为什么您不能 mock 位图?您应该测试 class 中的逻辑。您不需要测试 Context
位图加载功能,因为我确信它已经在 Android 框架中进行了测试。您已经对 工厂模式 有了一个好主意,因为您可以通过在您的应用程序中使用 myClass(bitmapFactory)
并在您的测试中使用 myClass(mockFactory)
来注入一个模拟工厂进行测试。
如果您完全确定需要编写一个测试来涵盖位图加载,那么请研究像 robolectric 这样的测试框架,因为它可以提供 模拟上下文 对于这样的场景。
如果您需要 Context
的功能,则需要以某种方式将其传递给 MyClass
。但是,这并不意味着您需要静态存储 Context
。事实上,那将是一个非常糟糕的设计选择(看起来你已经知道了)。
如果您使用 Dagger,那么我有 this video 教程解释了如何构建依赖注入代码。这种结构的一部分确实是在处理 Context
个对象的复杂性。
现在,即使 MyClass
需要访问 Context
才能获取位图,这并不一定意味着您需要解析集成测试。
首先,你可以使用Robolectric - 这个库"mocks" Android 框架,我认为它支持从资源中获取位图。
但是,根据您的用例,还有一个更简单的选项。您真的需要特定的位图,还是只想确保 MyClass
对该位图执行特定的操作?
如果您需要作为资源添加的特定位图,请选择 Robolectric,但如果不需要,您需要的只是确保正确使用所获得的位图,然后您可以模拟位图。
为了增加可读性,简化测试,防止违反得墨忒耳法则,我建议你把Context
换成这个class:
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
.
一旦你这样做了,在 return 模拟 Bitmap
的测试中通过模拟 BitmapRetriever
将很简单当 MyClass
要求它时。然后你可以在那个模拟上断言各种条件。