使用 firebase 数据库抛出错误进行测试

test with firebase database throwing error

我在我的项目中使用 firebase,我正在测试包括 firebase 组件在内的所有功能,我最近尝试测试 firebase 数据库,但它抛出了一个错误,我无法理解是否有人可以提供帮助,我将不胜感激,谢谢

  Attempt to invoke virtual method 'com.google.firebase.database.DatabaseReference com.google.firebase.database.DatabaseReference.child(java.lang.String)' on a null object reference
    at com.revert.journey.app.chatui.ChatHomeActivityTest.testCaseSendMessage
  @Test
    fun testCaseSendMessage(){
        val databaseMock = mock(DatabaseReference::class.java)
        ServiceLocator.reference = databaseMock
        `when`(databaseMock.child("Messages").child("1251515").setValue(Utils.message()))
            .thenReturn(isNotNull())

    }
    val messageMap = hashMapOf<String,Any>()
        messageMap["userName"] = userName
        messageMap["userMessage"] = message
        messageMap["userPic"] = userPic
        messageMap["messageTiming"] = Calendar.getInstance().timeInMillis.toString()
        messageMap["chatImage"] = downloadUrl
        messageMap["uid"] = firebaseAuth.currentUser!!.uid

        ServiceLocator.reference
            .child("Messages")
            .child(System.currentTimeMillis().toString())
            .setValue(messageMap).await()
object ServiceLocator {

    var firebaseAuth = FirebaseAuth.getInstance()
    var reference = FirebaseDatabase.getInstance().reference

}

 var base = ServiceLocator.reference.child("Messages")
 var child = base.child(System.currentTimeMillis().toString())
 child.setValue(messageMap).await()

如果你想模拟完整的调用链,你可以像这样为中间状态创建模拟(我不知道这里用于实时数据库的所有正确类型,但类似的方法适用于 Firestore)

val databaseMock = mock(DatabaseReference::class.java)
val childMock = mock(Reference::class.java)
val mockTask = mock(??) // set type to whatever "setValue" returns

doReturn(childMock).`when`(databaseMock).child(anyString())
doReturn(childMock).`when`(childMock).child(anyString())
doReturn(mockTask).`when`(childMock).setValue(any())

如果您想实际测试是否设置了正确的值,您可以向 mock 添加一个侦听器以拦截传递给它的实际值

doAnswer { invocation ->
    val args = invocation.arguments
    val l = args[0] as Map<String,Any>
    //add tests here to assert that the map values you sent are correct
    null
}.`when`(childMock).setValue(any())

调试技巧

如果您想诊断在这种情况下发生了什么,您可以将真实代码中的链式调用更改为类似于下面的代码。然后,如果调用之一 returns null 您将确切知道它是哪一个,并且可以为其添加缺少的模拟。

val db = ServiceLocator.reference
val cm = db.child("Messages")
val ct = cm.child(System.currentTimeMillis().toString())
val response = ct.setValue(messageMap)
response.await()

None 这些调用应该在测试中访问您的数据库,因此实际的数据库模式无关紧要。重要的是正确设置模拟(因为无论如何你都在使用模拟数据库)