Android Studio unit testing: read data (input) file
AndroidUnit TestingAndroid StudioAndroid 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)
-
Ensure you're using at least Android Gradle Plugin version 1.1. Follow the link to set up Android Studio correctly.
-
Create
test
directory. Put unit test classes injava
directory and put your resources file inres
directory. Android Studio should mark them like follow: -
Create
gradle
task to copy resources into classes directory to make them visible forclassloader
:android{ ... } task copyResDirectoryToClasses(type: Copy){ from "${projectDir}/src/test/res" into "${buildDir}/intermediates/classes/test/debug/res" } assembleDebug.dependsOn(copyResDirectoryToClasses)
-
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()); }
-
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):
- Put your files in
src/androidTest/assets
folder - 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
Step(3) put json file into resources folder(app/src/test/resources
)
Please look at attached screenshot for Step(3) result
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")
Reference on medium: https://medium.com/mobile-app-development-publication/android-reading-a-text-file-during-test-2815671e8b3b