androidunit-testingkotlinjunitmockwebserver

How can I read json file in local test on Android Studio?


I am testing with MockWebServer.

And I need a lot of json files for request and response data.

Hard coded json values seem messy and I want to create json files instead.

So, I created json files in resources(test). And I tried to read file with these methods.

object TestHelper {
    fun read(fileName: String): String {
        val resource = javaClass.classLoader?.getResource(fileName)
        return resource?.readText() ?: ""
    }

    fun readJson(fileName: String): String {
        val byteArray = readBinaryFileFromResources(fileName)
        val sb = StringBuilder("")

        byteArray.forEach {
            println("byte: $it")
            sb.append(it as Char)
        }

        return sb.toString()
    }

    @Throws(IOException::class)
    fun readBinaryFileFromResources(fileName: String): ByteArray {
        var inputStream: InputStream? = null
        val byteStream = ByteArrayOutputStream()
        try {
            inputStream = javaClass.classLoader?.getResourceAsStream(fileName)

            var nextValue = inputStream?.read() ?: -1

            while (nextValue != -1) {
                byteStream.write(nextValue)
                nextValue = inputStream?.read() ?: -1
            }
            return byteStream.toByteArray()
        } catch (e: Exception) {
            println(e.stackTraceToString())
            return byteStream.toByteArray()
        } finally {
            inputStream?.close()
            byteStream.close()
        }
    }
}

None of them seems work. What's the problem with this code?


Solution

  • I've had trouble with this before, and I believe it has to do with getting the correct classLoader from the call site, as well as having resources in the src/test/resources not being accessible properly. I eventually got it to work by passing in the calling test class as a reified type parameter:

    inline fun <reified T> loadFileText(
        caller: T,
        filePath: String
    ): String =
        T::class.java.getResource(filePath)?.readText() ?: throw IllegalArgumentException(
            "Could not find file $filePath. Make sure to put it in the correct resources folder for $caller's runtime."
        )
    

    For my setup I have a separate shared module :testtools that I use testImplementation to include in my :app's gradle build so they don't get compiled into the production APK. I have my test resources in:

    /testtools/src/main/resources/customfolder
    

    And then calling this from a unit test class in :app like so:

    class UnitTestClass {
    
        @Test
        fun myTest() {
            loadFileText(this, "/customfolder/file_name.txt")
        }
    }
    

    You might have some luck putting your resources straight into /app/src/test/resources/customfolder, I haven't tried in a while.