【问题标题】:Android InstrumentationTestCase getFilesDir() returns nullAndroid InstrumentationTestCase getFilesDir() 返回 null
【发布时间】:2020-01-10 14:21:27
【问题描述】:

我正在使用InstrumentationTestCase 对我的应用程序的一个组件进行单元测试。

组件将数据持久化到内部存储,并使用Context::fileList(); 检索持久化文件。

我遇到以下问题:在应用程序(设备上)中使用此方法效果很好。但是,当我尝试使用InstrumentationTestCase 进行(Android-)单元测试(也在设备上)时,我在fileList() 方法中得到了NullPointerException。我挖掘了android源码,发现getFilesDir()(see source here)返回null并导致这个错误。

重现的代码如下:

public class MyTestCase extends InstrumentationTestCase
{   
    public void testExample() throws Exception
    {
        assertNotNull(getInstrumentation().getContext().getFilesDir()); // Fails
    }
}

我的问题是:这种行为是有意的吗?我能做些什么来规避这个问题?我是使用InstrumentationTestCase 对还是应该使用不同的东西?

我找到了this question,但我不确定这是否涵盖了我遇到的相同问题。

【问题讨论】:

  • 您是否尝试使用 getTargetContext() 而不是 getContext()
  • 嗯,是的。 getTargetContext() 按预期工作,但我希望测试(或多或少)独立于应用程序运行。这就是我选择InstrumentationTestCase的原因。
  • 顾名思义,InstrumentationTestCase 是一个插桩测试,通过使用第二个测试应用来插装主应用以测试 Android 组件,例如正确渲染活动或正确处理用户交互。独立于主应用运行测试应用没有多大意义。
  • @yorkw 是的,我已经怀疑这是否正确。因此,如果我需要准备好的数据集,您会建议以下内容吗?对当前数据执行“备份”,写入准备好的数据集,执行测试,删除测试数据,恢复备份?

标签: android unit-testing


【解决方案1】:

我认为您将测试数据与测试应用程序分开是正确的。

您可以通过执行以下命令为Instrumentation 应用程序创建files 目录来解决Null 的问题

adb shell
cd /data/data/<package_id_of_instrumentation_app>
mkdir files

您只能在模拟器或 root 设备上执行上述操作。

那么你的问题的测试不会失败。我做到了并将名为tst.txt的文件上传到files目录,以下所有测试均成功:

assertNotNull(getInstrumentation().getContext().getFilesDir());
assertNotNull(getInstrumentation().getContext().openFileInput("tst.txt"));
assertNotNull(getInstrumentation().getContext().openFileOutput("out.txt", Context.MODE_PRIVATE));

但我认为向测试项目提供数据更方便的方法是使用测试项目的assets,您可以简单地保存一些文件并打开它们:

assertNotNull(getInstrumentation().getContext().getAssets().open("asset.txt"));

或者如果您想将一些测试结果保存到文件中,您可以使用ExternalStorage:

File extStorage = Environment.getExternalStorageDirectory();
assertNotNull(extStorage);

【讨论】:

  • +1 不错。 shell 修复允许我基于 Realm.io 对数据持久性进行单元测试。
  • 为什么文件目录首先不存在?
【解决方案2】:

@Blackbelt mentioned in his comment 使用 getTargetContext() 而不是 getContext()。我错过了评论,几个小时后,试图弄清楚how to Realm.init() from an Android instrumented tests,我发现我需要来自getTargetContext()的上下文...(一路上,我试图context.filesDir.mkdirs()

package com.github.ericytsang

import androidx.test.platform.app.InstrumentationRegistry
import org.junit.Test

class InstrumentedTest {

    private val context = InstrumentationRegistry.getInstrumentation().targetContext

    @Test
    fun can_mkdirs() {
        assert(context.filesDir.mkdirs())
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-22
    • 2012-05-28
    • 2014-12-05
    • 2021-07-07
    • 2013-06-27
    • 1970-01-01
    相关资源
    最近更新 更多