【问题标题】:test with firebase database throwing error使用 firebase 数据库抛出错误进行测试
【发布时间】:2022-01-16 02:45:16
【问题描述】:

我在我的项目中使用 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()
  • ServiceLocator 类
object ServiceLocator {

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

}
  • 我的 Firebase 中的图像示例

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

【问题讨论】:

  • 错误是什么?您的毫秒时间可能与您的模拟值“1251515”不匹配,可能想在那里使用anyString()
  • 我收到一个错误,即使用 nullpointerexception 调用数据库,我也包含了错误和服务定位器类,谢谢
  • 我猜System.currentTimeMillis().toString() 不等于1251515,所以没有应用模拟并且方法返回null。尝试将您的模拟更改为使用 anyString() 而不是 "1251515"
  • 我确实写了 anyString() ,但它仍然显示相同的错误奇怪
  • 好的,下一步是将调用链分解成单独的部分,这样您就可以找出哪个是空的(val c1 = ServiceLocator.reference.child("Messages")val c2 = c1.child(...)val t = c2.setValue(...)t.await() 等)。也许也可以尝试模拟中间状态(doReturn(databaseChild).when(databaseMock).child(anyString())

标签: android kotlin firebase-realtime-database android-espresso


【解决方案1】:

如果您想模拟完整的调用链,您可以像这样为中间状态创建模拟(我不知道此处用于实时数据库的所有正确类型,但类似的方法适用于 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())

调试提示

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

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

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

【讨论】:

  • 它通过将代码分成几部分来工作,非常感谢
  • @Taki 很高兴它成功了
猜你喜欢
  • 2021-04-08
  • 2023-03-04
  • 2019-04-18
  • 2017-09-03
  • 1970-01-01
  • 2020-11-26
  • 1970-01-01
  • 2011-06-02
  • 2022-08-02
相关资源
最近更新 更多