Android Studio单元测试:读取数据(输入)文件


96

在单元测试中,如何在不对路径进行硬编码的情况下从(桌面)文件系统上的json文件读取数据?

我想从文件中读取测试输入(用于我的解析方法),而不是创建静态字符串。

该文件与我的单元测试代码位于同一位置,但是如果需要,我也可以将其放置在项目中的其他位置。我正在使用Android Studio。


3
我尝试了几乎所有与IOUtils.toString(this.getClass()。getResourceAsStream(“ test_documents.json”),“ UTF-8”)的组合,它始终返回null。可能是因为文件不会包含在jar中。
2015年

我们是否在谈论涉及android模拟器/设备的单元测试?
AndroidEx 2015年

@ Android777我认为我们正在谈论的是最新版本的Android Studio tools.android.com/tech-docs/unit-testing-support中
akhy,2015年

@弗兰克你在test_documents.json哪里?资产目录?
akhy 2015年

是的,我们正在谈论新的单元测试支持,而不涉及仿真器/设备。我没有将其放置在资产目录中,因为那样它将与实时apk打包在一起。我将其放置在与测试(java)文件相同的文件夹中。
2015年

Answers:


149

根据android-gradle-plugin版本:

1. 1.5版或更高版本:

只需将json文件放入src/test/resources/test.json并引用为

classLoader.getResource("test.json"). 

无需修改gradle。

2. 1.5以下的版本:(或由于某种原因上述解决方案不起作用)

  1. 确保您至少使用了Android Gradle插件1.1版。按照链接正确设置Android Studio。

  2. 创建test目录。将单元测试类放在java目录中,并将您的资源文件放在res目录中。Android Studio应该将它们标记为如下:

    在此处输入图片说明

  3. 创建gradle任务以将资源复制到classes目录中,以使其可见classloader

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
    
  4. 现在,您可以使用此方法获取File文件资源的引用:

    private static File getFileFromPath(Object obj, String fileName) {
        ClassLoader classLoader = obj.getClass().getClassLoader();
        URL resource = classLoader.getResource(fileName);
        return new File(resource.getPath());
    }
    
    @Test
    public void fileObjectShouldNotBeNull() throws Exception {
        File file = getFileFromPath(this, "res/test.json");
        assertThat(file, notNullValue());
    }
    
  5. 通过Ctrl+ Shift+ F10对整个类或专门的测试方法进行单元测试。

1
太棒了!您的编辑(无需工具测试)就像一个魅力,谢谢!
弗兰克

4
这是一个不错的解决方案,但并不总是有效。如果执行运行clean任务,然后运行testDebug,它将失败。基本上,开发人员需要知道他必须在testDebug之前运行assembleDebug任务。你们有什么建议可以改善吗?
joaoprudencio 2015年

18
使用带有Android插件1.5.0的AndroidStudio 1.5,将您的json文件放在此处,src/test/resources/test.json并将其引用为classLoader.getResource("test.json")。无需修改gradle。内部的嵌套文件夹resources也可以正常工作。
Sergii Pechenizkyi 2015年

6
答案不完整。什么classLoader啊 这行代码放在哪里?返回结果如何处理?请提供更完整的代码。-1
voghDev

3
./src/test/resources/file.txt在科特林阅读:TestClassName::class.java.getResource("/file.txt")!!.readText()
Erik

76

对于本地单元测试(与工具测试),您可以将文件放在下面src/test/resources并使用classLoader读取它们。例如,以下代码myFile.txt在资源目录中打开文件。

InputStream in = this.getClass().getClassLoader().getResourceAsStream("myFile.txt");

它与

  • Android Studio 1.5.1
  • gradle插件1.3.1

这对我不起作用,请在此处查看我的问题stackoverflow.com/questions/36295824/…–
泰勒·帕夫

5
当我从“ src / test / res”更改为“ src / test / resources”时,这对我有用。使用Android Studio 2.0 RC 3,gradle:2.0.0-rc3
Alex Bravo

如预期般运作。但是即使文件在“ src / test / resources /”(例如:“ rules.xml”)下不可用,测试也通过了,但是在这种情况下InputStream结果为null。
阿南德·克里什(Anand krish),

4
科特林:val myFile = ClassLoader.getSystemResource("myFile.txt").readText()
jj。

像魅力一样工作!
阿米·班达里

15

就我而言,解决方案是将其添加到gradle文件中

sourceSets {
    test.resources.srcDirs += 'src/unitTests/resources'
  } 

之后,一切由AS 2.3.1找到

javaClass.classLoader.getResourceAsStream("countries.txt")

我做了非常类似的事情(Kotlin):1.在以下位置创建文件夹和文件:root/app/src/test/resources/test.json 2.读取像这样的数据:val jsonFile = ClassLoader.getSystemResource("test.json").readText()
jj。

8

Android Studio中的测试资源存在很多问题,因此为了清晰起见,我设置了一些测试。在我的 mobile(Android应用程序)项目中,添加了以下文件:

mobile/src/test/java/test/ResourceTest.java
mobile/src/test/resources/test.txt
mobile/src/test/resources/test/samePackage.txt

测试类(所有测试通过):

assertTrue(getClass().getResource("test.txt") == null);
assertTrue(getClass().getResource("/test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getResource("samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getResource("/test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));
assertTrue(getClass().getClassLoader().getResource("test.txt").getPath().endsWith("test.txt"));
assertTrue(getClass().getClassLoader().getResource("test/samePackage.txt").getPath().endsWith("test/samePackage.txt"));

在相同的根项目我有一个Java的(不是安卓)项目data。如果我将相同文件添加到数据项目中:

data/src/test/java/test/ResourceTest.java
data/src/test/resources/test.txt
data/src/test/resources/test/samePackage.txt

然后,如果我从Android Studio执行上述所有测试,均将失败,但它们会通过并通过命令行传递./gradlew data:test。为了解决这个问题,我使用了这个技巧(在Groovy中)

def resource(String path) {
    getClass().getResource(path) ?:
            // Hack to load test resources when executing tests from Android Studio
            new File(getClass().getClassLoader().getResource('.').path
                    .replace('/build/classes/test/', "/build/resources/test$path"))
}

用法: resource('/test.txt')

Android Studio 2.3,Gradle 3.3


很好的答案(搜索45 45分钟后)。它触及了几个问题的核心,并使其易于使用测试本身来复制结果。Fwiw,在AS 2.3.1,Gradle 2.3.1中,getClassLoader()版本按预期工作。也就是说,他们找到了文件,它们都可以从Android Studio以及从我的macOS机器上的命令行以及Linux CI服务器(CircleCI)上运行。所以我要继续下去,希望Gradle 3.3以后不会破坏它……
mm2001

真好!我在这里看到了相同的资源加载问题。AS 2.3.2,Gradle 3.3。由于build/resources/test未包含在交互式类路径中,因此这些测试从命令行运行,但无法通过AS运行。
马克·麦肯纳

6

如果转到运行->编辑配置-> JUnit,然后为单元测试选择运行配置,则存在“工作目录”设置。那应该指向您的json文件在哪里。请记住,这可能会破坏其他测试。


并且比使用this.getClass()。getResourceAsStream(test.json)吗?我在项目的根目录中添加了文件,但仍找不到文件。
弗兰克

这可以用于使用new File()或类似方式加载文件,但不适用于上述的类路径加载方法。这也有些棘手,因为每个新的运行配置都需要设置工作目录,并且默认情况下,AS和Gradle命令行喜欢使用不同的工作目录...这样的痛苦
Mark McKenna

4

我虽然应该在这里添加我的发现。我知道这有点旧,但是对于较新版本的Gradle,那里没有src / test / resources目录,但是整个项目只有一个资源目录,您必须将此行添加到Gradle文件中。

android {
   testOptions {
      unitTests {
         includeAndroidResources = true
      }
    }
}

这样,您可以通过以下方式访问资源:

 this.getClass().getClassLoader().getResourceAsStream(fileName);

我一直在搜索此内容,但找不到答案,因此我决定在这里帮助其他人。


1

实际上,这是对Instrumentation Tests(运行Android Studio版本3.5.3,Android Gradle插件版本3.5.3,Gradle版本6.0.1)的工作方式:

  1. 将文件放在src/androidTest/assets文件夹中
  2. 在您的测试文件中:

InputStream is = InstrumentationRegistry.getInstrumentation().getContext().getAssets().open("filename.txt");

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.