使用 mockito 模拟 firebase 用户时出错

getting error mocking firebase user with mockito

我正在尝试模拟一个 firebase 用户来为我的测试提供它,我模拟了 firebase 身份验证 class 从中我得到了当前登录用户的 uid 但对于某些人它一直在抛出同样的错误,我将不胜感激你们的帮助

    private fun getUserProfileInfo(){
        val db = ServiceLocator.reference
        val child = db.child("Users")
        val user = ServiceLocator.firebaseUser
        val value = child.child(user!!.uid)

           value.addListenerForSingleValueEvent(object  : ValueEventListener {
                override fun onDataChange(snapshot: DataSnapshot) {
                    if(snapshot.exists()){
                        val model = snapshot.getValue(ProfileModel::class.java)
                        userName = model!!.firstName
                        userPic = model.profilePicUrl
                    }
                }
                override fun onCancelled(error: DatabaseError) {
                }

            })
    }
  @Test
    fun testCaseProfileInfo(){
        val firebaseUserMock = mock(FirebaseUser::class.java)
        val firebaseMock = mock(FirebaseAuth::class.java)
        val databaseMock = mock(DatabaseReference::class.java)

        ServiceLocator.firebaseAuth = firebaseMock
        ServiceLocator.firebaseUser = firebaseUserMock
        ServiceLocator.reference = databaseMock

        doReturn(firebaseUserMock).`when`(firebaseMock).currentUser
        val uid = doReturn("123").`when`(firebaseMock).uid // error here

        doReturn(databaseMock.child("Users")
            .child(uid!!))
            .`when`(databaseMock).get()
    }
object ServiceLocator {
    var firebaseAuth = FirebaseAuth.getInstance()
    var reference=FirebaseDatabase.getInstance(Utils.DATABASE_URL).reference
}

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at com.revert.journey.app.chatui.FriendsRequestActivityTest.testCaseProfileInfo


 @Test
    fun testCaseProfileInfo(){
        val userMock = mock(FirebaseUser::class.java)
        val firebaseMock = mock(FirebaseAuth::class.java)
        val databaseMock = mock(DatabaseReference::class.java)

        ServiceLocator.firebaseAuth = firebaseMock
        ServiceLocator.firebaseUser = userMock
        ServiceLocator.reference = databaseMock

        doReturn(userMock).`when`(firebaseMock).currentUser
        doReturn("123").`when`(userMock)!!.uid

        doReturn(databaseMock
            .child("Users")
            .child("123")) //  ( null pointer exception on this string)..
            .`when`(databaseMock).get()
    }

您还需要从 FirebaseAuth 模拟 returned 用户,像这样

val userMock = mock(FirebaseUser::class.java)

doReturn(userMock).`when`(firebaseMock).currentUser
doReturn("123").`when`(userMock).uid

如果将生产代码拆分成更多的步骤(像这样),您可能会看到 currentUser 为 null

val db = ServiceLocator.reference
val child = db.child("Users")
val user = ServiceLocator.firebaseAuth.currentUser
val uid = user?.uid ?: return
val value = child.child(uid)

使用 mocked classes 时要记住的重要一点是 all 它们的方法将 return null 除非你特别设置 return为了他们。

要完整模拟上述调用,您需要以下模拟

如果您希望您的方法可调用,则需要以下模拟。您的测试方法 根本不与 Firebase 交互 - 它是假的 class (模拟),因此您必须明确告诉它 return 当您调用方法或从中获取属性。您的测试目标是定义这些 return 值,以便从您可以测试的方法中获得一些有用的操作。

@Test
 fun testCaseProfileInfo(){
    val firebaseMock = mock(FirebaseAuth::class.java)
    val databaseMock = mock(DatabaseReference::class.java)
    val userMock = mock(FirebaseUser::class.java)
    val childMock = mock(Reference::class.java)
    
    ServiceLocator.firebaseAuth = firebaseMock
    ServiceLocator.reference = databaseMock
    
    
    // Tell the firebaseMock what to return when 
    // you call "currentUser"
    doReturn(userMock).`when`(firebaseMock).currentUser
    
    // Tell "userMock" to return "123" when you call
    // currentUser.uid in your production method
    doReturn("123").`when`(userMock).uid
    
    // Tell the database mock what to return when
    // you call db.child("Users")
    doReturn(childMock).`when`(databaseMock).child("Users")
    
    // Tell the users mock what to return when you
    // call db.child(uid)
    doReturn(childMock).`when`.usersMock("123")
    
    // Method should now be callable, but adding a listener for the event would be good to test
}

对于更完整的示例,请考虑使用以下方法获取用户 ID(如果他们已登录),您希望使用 mock 进行测试。

fun getUID(): String? {
    val uid = ServiceLocator.firebaseAuth.currentUser?.uid
    return uid
}

您可以按如下方式为此编写测试

@Test
fun testUserNotLoggedIn(){
    val firebaseMock = mock(FirebaseAuth::class.java)
    
    ServiceLocator.firebaseAuth = firebaseMock
    doReturn(null).`when`(firebaseMock).currentUser
    
    assertNull(getUID())
}
@Test
fun testUserLoggedIn(){
    val firebaseMock = mock(FirebaseAuth::class.java)
    val userMock = mock(FirebaseUser::class.java)
    
    ServiceLocator.firebaseAuth = firebaseMock
    doReturn(userMock).`when`(firebaseMock).currentUser
    doReturn("123").`when`(userMock).uid
    
    assertEqual("123", getUID())
}