单元测试 - 如何构建 Firebase 模拟?

Ske*_*Dev 5 junit unit-testing mockito firebase google-cloud-firestore

我正在使用 Mockito 框架对我的应用程序进行单元测试。

TL; 博士

我应该为类的每个可能结果创建一个模拟并在@Before 中设置它们的行为,还是应该为每个类只创建一个模拟,然后在使用它们的每个测试中定义它们的行为?

语境

现在我正在测试DataRepository,有getPosts(String postId)。通过 DIDataRepository接收FirebaseFirestore实例。

getPosts返回Maybe<List<Post>>带有以下代码的 a:

fun getPosts(companyId: String): Maybe<List<Post>> {
    return Maybe.create { emitter ->
        firestore.collection("companies/$companyId/posts").get()
                .addOnCompleteListener {
                    if (it.isSuccessful) {
                        if (it.result.isEmpty) {
                            emitter.onComplete()
                        } else {
                            emitter.onSuccess(it.result.toObjects(Post::class.java))
                        }
                    } else {
                        emitter.onError(it.exception ?: UnknownError())
                    }
                }
    }
}
Run Code Online (Sandbox Code Playgroud)

问题

为了测试这个函数和各种情况(成功/空/失败),我必须模拟 FirebaseFirestore,然后是 CollectionReference,然后是任务,然后是 OnCompleteListener(带有参数捕获器)等等。基本上什么都有。

当我嘲笑任务时,我应该

一种。创建一个successfulTaskMock我在@Before 中设置的总是成功的和失败的?与有效/空validQuerySnapshot/相同的事情emptyQuerySnapshot

湾 只创建一个taskMock然后在测试中直接改变它的返回值?(使 taskMock.isSuccessful 在成功测试中返回 true,在失败测试中返回 false)

我看过一些 GitHub 存储库:有些做 a.,有些做 b。

问题a。是我最终会为同一个班级提供大量模拟,但测试非常干净和可读。

b 的问题。我应该在每次测试开始时设置每个模拟,从而有很多样板代码。

结论

我读过我可以使用深度模拟来只创建调用的最终结果(QuerySnapshot,而不是 Firestore + Collection + Task 等),但这似乎很不受欢迎,我明白为什么。

也许还有第三种我不知道的方式。任何建议都非常感谢。

非常感谢。