getTargetContext() 和 getContext(在 InstrumentationRegistry 上)有什么区别?

What's the difference between getTargetContext() and getContext (on InstrumentationRegistry)?

我正在使用新的 Android 测试支持库 (com.android.support.test:runner:0.2) 进行 运行 仪器测试 (a.k.a 设备或​​模拟器测试)。

我用 @RunWith(AndroidJUnit4.class) 注释我的测试 class 并使用 Android Studio 来 运行 它们。

对于我的测试用例,我需要一个 Context 实例。我可以用 InstrumentationRegistry 得到它,但它有两个上下文相关的方法,不清楚有什么区别。

InstrumentationRegistry.getContext()InstrumentationRegistry.getTargetContext() 有什么区别?

InstrumentationRegistry is an exposed registry instance that holds a reference to the instrumentation running in the process and it's arguments and allows injection of the following instances:

  • InstrumentationRegistry.getInstrumentation(), returns the Instrumentation currently running.
  • InstrumentationRegistry.getContext(), returns the Context of this Instrumentation’s package.
  • InstrumentationRegistry.getTargetContext(), returns the application Context of the target application.
  • InstrumentationRegistry.getArguments(), returns a copy of arguments Bundle that was passed to this Instrumentation. This is useful when you want to access the command line arguments passed to Instrumentation for your test.

编辑:

So when to use getContext() vs getTargetContext()?

文档没有很好地解释差异,所以这是我的 POV:

您知道,当您在 Android 上进行仪器测试时,您有两个应用程序:

  1. 测试应用程序,执行您的测试逻辑并测试您的 "real" 应用程序
  2. "real" 应用(您的用户将会看到)

因此,当您编写测试并且想要加载真实应用程序的资源时,请使用getTargetContext()

如果您想使用测试应用程序的资源(例如,您的一项测试的测试输入),请调用getContext()

您可能需要 InstrumentationRegistry.getContext() 才能访问测试用例的原始资源。

例如,要在测试用例中访问 app/src/androidTest/res/raw/resource_name.json

final Context context = InstrumentationRegistry.getContext(); InputStream is = context.getResources().openRawResource(com.example.package.test.R.raw.resource_name);

我花了好几个小时才弄明白。

InstrumentedTest 用例有一个上下文成员,它在设置中设置如下:

context = InstrumentationRegistry.getTargetContext();

这用于打开文件,尤其是类似的东西:

String filenameOriginal = context.getCacheDir() + "/initial.csv";

现在我决定我需要使用一些 在插桩测试中可用的资源,我不想将此资源与发布版本一起分发。 因此我重新创建了测试下的资源目录:

app\src\androidTest
└───res
    └───raw
            v1.csv

但是为了能够在代码中使用它,我必须这样调用:

    public static Uri resourceToUri(Context context, int resID)
    {
        return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
                context.getResources().getResourcePackageName(resID) + '/' +
                context.getResources().getResourceTypeName(resID) + '/' +
                context.getResources().getResourceEntryName(resID));
    }

    resourceToUri(context, R.raw.v1)

总是 失败,因为 R.raw.v1 巧合地对应于主应用程序中我的 R 资源文件中实际存在的内容。通过在插桩测试中使用资源,生成了两个 R 文件。为了解决这个问题,我必须包含测试 R 文件:

import com.my_thing.app.my_app.test.R;

resourceToUri 调用仍然会失败。

问题是,我一定没有使用 InstrumentationRegistry.getTargetContext() 而是 InstrumentationRegistry.getInstrumentation().getContext() 来获取 R.raw.v1 的资源,所以我盲目地替换了整个测试的上下文设置class 到

context = InstrumentationRegistry.getInstrumentation().getContext();

它在特定测试中运行良好,但测试用例中的其他测试开始失败,因为我在上面使用的 filenameOriginal 权限被拒绝。

原来,通过将上下文替换为检测上下文,我获得了我的应用程序无法访问的路径,我得到了 FileNotFoundExceptionpermission denied 而没有 GrantTestRule 或其他事情会成功的。

所以在使用这些上下文时要小心,它可能会浪费你的时间:/