模拟访问/资产文件

时间:2014-08-17 16:35:25

标签: android unit-testing junit assets

我试图为访问/asset中的文件的类创建一个测试单元,并且就我实验而言,如果不改变被测试类的逻辑,我认为没办法做到这一点

我想要完成的是创建一个环境,我可以将我的类指向我喜欢的资产文件(而不是最初在代码中指出的那个),这样我就可以用它运行多个测试,所以例如,如果我的原始代码看起来像:

ctx.getAssets().open("config.txt")

我可以改为打开

bogus_config.txt
ok_config.txt
nonexisting_config.txt

到目前为止,我已经尝试过:

  • 创建MockContext,但由于AssetManager中的所有内容都是final,我认为无法获得所需的文件
  • 使用带有特定前缀的RenamingDelegatingContext,但前缀并不适用于资产档案......

有没有更好的方法(例如某些Java Magik Reflection Trick(Tm))来实现我想要的目标?

尽管我对一般的单元测试非常陌生,但我知道我可以选择以下任何一种解决方案:

  • 将文件移动到raw并使用Resources(但是在使用资产时我将采取哪些措施?这会很高兴知道......)
  • 在课堂上公开文件的名称并在测试单元内更改(只是开玩笑...... 呃!! :p
  • 创建我的方法的公共环绕以使用特定文件而不是默认使用的文件,并在方法前加junit_来记录它仅供测试例程使用(可能是我最终会做什么)

但我仍然认为原来的问题可能会引起一些兴趣,所以欢迎提出任何建议

谢谢!

2 个答案:

答案 0 :(得分:1)

  > I see no way do that without altering the logic of the class being tested.

我同意,但更改很小:将代码ctx.getAssets().open("config.txt")移动到受保护的方法InputStream openConfig(Context ctx)中,您可以在测试中轻松覆盖/伪造/模拟。如果使用Eclipse或Androidstudio标记语句并执行context-menu Refactor / Extract-Method。

答案 1 :(得分:0)

您可以使用这种方式

class AssetsUtils {

    companion object {

        fun <T> loadResponse(
            path: String,
            tClass: Class<T>?,
            isPrettyPrinting: Boolean? = false,
            isUnitTest: Boolean? = true
        ): T {

            val json = File(
                "src/${if (isUnitTest == true) {
                    "test"
                } else {
                    "androidTest"
                }}/assets/${path}"
            ).bufferedReader().use {
                it.readText()
            }

            val gson = GsonBuilder()
                .serializeNulls()
                .setPrettyPrinting()
                .create()

            val model = gson.fromJson(json, tClass)

            if (isPrettyPrinting == true) {
                println("Load Response ------------------------------------------------------------------------------------------------")
                println()
                println("Response file: $path")
                println(gson.toJson(model))
                println()
                println("Model: $model")
                println()
                println("--------------------------------------------------------------------------------------------------------------")
            }

            return model
        }
    }
}

示例: “ C://ProjectA/app/src/test/asstes/mockApi/folder1/user.json”中的文件

AssetsUtils.loadResponse(
       "mockApi/folder1/user.json",
       UserModel::class.java
)