Android Studio unit testing: read data (input) file

AndroidUnit TestingAndroid Studio

Android Problem Overview


In a unit test, how can I read data from a json file on my (desktop) file system, without hardcoding the path?

I would like to read test input (for my parsing methods) from a file instead of creating static Strings.

The file is in the same location as my unit testing code, but I can also place it somewhere else in the project if needed. I am using Android Studio.

Android Solutions


Solution 1 - Android

Depending on android-gradle-plugin version:

1. version 1.5 and higher:

Just put json file to src/test/resources/test.json and reference it as

classLoader.getResource("test.json"). 

No gradle modification is needed.

2. version below 1.5: (or if for some reason above solution doesn't work)

  1. Ensure you're using at least Android Gradle Plugin version 1.1. Follow the link to set up Android Studio correctly.

  2. Create test directory. Put unit test classes in java directory and put your resources file in res directory. Android Studio should mark them like follow:

    enter image description here

  3. Create gradle task to copy resources into classes directory to make them visible for classloader:

    android{
       ...
    }
    
    task copyResDirectoryToClasses(type: Copy){
        from "${projectDir}/src/test/res"
        into "${buildDir}/intermediates/classes/test/debug/res"
    }
    
    assembleDebug.dependsOn(copyResDirectoryToClasses)
    
  4. Now you can use this method to get File reference for the file resource:

    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. Run unit test by Ctrl+Shift+F10 on whole class or specyfic test method.

Solution 2 - Android

For local unit tests (vs. instrumentation tests), you can put files under src/test/resources and read them using classLoader. For example, following code opens myFile.txt file in the resources directory.

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

It worked with

  • Android Studio 1.5.1
  • gradle plugin 1.3.1

Solution 3 - Android

In my case, the solution was to add to the gradle file

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

After it everything was found by AS 2.3.1

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

Solution 4 - Android

I though I should add my findings here. I know this is a little old but for the newer versions of Gradle, where there is NO src/test/resources directory, but only one single resources directory for the whole project, you have to add this line to your Gradle file.

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

By doing this you can access your resource with:

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

I've been searching for this and could not find an answer, so I decided to help others here.

Solution 5 - Android

I've had plenty of problems with test resources in Android Studio so I set up a few tests for clarity. In my mobile (Android Application) project I added the following files:

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

The test class (all tests passes):

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"));

In the same root project I have a Java (not Android) project called data. If I add the same files to the data project:

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

Then all the tests above will fail if I execute them from Android Studio, but they pass on the command line with ./gradlew data:test. To get around it I use this hack (in 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"))
}

Usage: resource('/test.txt')

Android Studio 2.3, Gradle 3.3

Solution 6 - Android

If you go to Run -> Edit configurations -> JUnit and then select the run configuration for your unit tests, there is a 'Working directory' setting. That should point to wherever your json file is. Keep in mind this might break other tests.

Solution 7 - Android

Actually, this is what worked for me with Instrumentation Tests (Running Android Studio version 3.5.3, Android Gradle Plugin version 3.5.3, Gradle version 6.0.1):

  1. Put your files in src/androidTest/assets folder
  2. In your test file:

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

Solution 8 - Android

Step(1) open Android Studio select Project view

Step(2) and create resources directory under test.

Please look at attached screenshot for Step(2) result

enter image description here

Step(3) put json file into resources folder(app/src/test/resources)

Please look at attached screenshot for Step(3) result

enter image description here

Step(4) Create a common class to handle reading local json files and converting to respective models using Gson

Example :-

object TestHelper {
    private val gson = Gson()

    fun loadJsonAsString(fileName: String): String {
        val inputStream = javaClass.getResourceAsStream("/$fileName")
        return getStringFromInputStream(inputStream)
    }

    @Throws(IOException::class)
    private fun getStringFromInputStream(stream: InputStream?): String {
        var n = 0
        val buffer = CharArray(1024 * 4)
        val reader = InputStreamReader(stream, "UTF8")
        val writer = StringWriter()
        while (-1 != reader.read(buffer).also { n = it }) writer.write(buffer, 0, n)
        return writer.toString()
    }

    fun <T> convertJsonToModel(jsonString: String, classT: Class<T>): T{
        return gson.fromJson(jsonString, classT)
    }
}

Step(5) load the json file stored locally in resources directory created in Step(2)

val GET_USER_INFORMATION_RESPONSE_FILE_NAME = "user_response.json"
val jsonString = loadJsonAsString(GET_USER_INFORMATION_RESPONSE_FILE_NAME)
        val networkStatusResponse =
            convertJsonToModel(jsonString, UserResponse::class.java)

Step(6) at the end of Step(5) you would have converted local json file into required model class that can be used to write your unit tests.

Solution 9 - Android

In my case I only needed to create resources folder into test folder and put my resource file in that folder. Then, in the test simply load the file as resource stream with:

val inputStream =
        this.javaClass.classLoader?.getResourceAsStream("gallery.xml")

enter image description here

Reference on medium: https://medium.com/mobile-app-development-publication/android-reading-a-text-file-during-test-2815671e8b3b

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFrankView Question on Stackoverflow
Solution 1 - AndroidklimatView Answer on Stackoverflow
Solution 2 - Androiduser3113045View Answer on Stackoverflow
Solution 3 - Androidar-gView Answer on Stackoverflow
Solution 4 - AndroidRaphael AyresView Answer on Stackoverflow
Solution 5 - AndroidLoveView Answer on Stackoverflow
Solution 6 - AndroidTas MorfView Answer on Stackoverflow
Solution 7 - AndroidMicheleView Answer on Stackoverflow
Solution 8 - AndroidVikash Kumar TiwariView Answer on Stackoverflow
Solution 9 - AndroidNicola GallazziView Answer on Stackoverflow