0

I have login form which sign in the user using firebase and i'm trying to test the login functionality by writing some code and i used Mockito to mock the firebase class but for someone it keeps failing and i think there is something , if someone could help fix the issue , Thank you

  • This is my code
@RunWith(AndroidJUnit4ClassRunner::class)
class LoginActivityTest {

    @get:Rule
    var scenario = ActivityScenarioRule(LoginActivity::class.java)
    private lateinit var emailEditText : TextInputLayout
    private lateinit var passwordEditText : TextInputLayout
    private lateinit var firebaseUser: FirebaseUser



 @Test
    fun testCaseRealUserLogin(){

        scenario.scenario.onActivity { it ->
            emailEditText = it.findViewById(R.id.loginEmail)
            passwordEditText = it.findViewById(R.id.loginPassword)
        }

        Looper.prepare()
        emailEditText.editText!!.setText("xxxxxx@gmail.com")
        passwordEditText.editText!!.setText("xxxxxx")

        onView(withId(R.id.loginBtn)).perform(click())

        //Mocking firebase
        val firebaseMock  = mock(FirebaseAuth::class.java)
        `when`(firebaseMock.signInWithEmailAndPassword("xxxxxxx","xxxxxxx"))
            .thenReturn(notNull())

        firebaseUser = firebaseMock.currentUser!!

        assertNotNull(firebaseUser)

    }
}
Taki
  • 3,290
  • 1
  • 16
  • 41

1 Answers1

1

Simple Answer. the activity not using the mocked class!!. it uses the real one FirebaseAuth.

So you need to supply the mocked class to the activity.

Simple approach is ServiceLocator pattern

First create a ServiceLocator.kt class

object ServiceLocator {

    var auth = Firebase.auth

}

And use it in the production code instead of instantiating the auth object

// in activity to sign in
ServiceLocator.auth.createUserWithEmailAndPassword(email, password)

Second you need to replace the real with the mocked class when testing

fun testCaseRealUserLogin(){

    scenario.scenario.onActivity { it ->
        emailEditText = it.findViewById(R.id.loginEmail)
        passwordEditText = it.findViewById(R.id.loginPassword)
    }

    Looper.prepare()
    emailEditText.editText!!.setText("xxxxxx@gmail.com")
    passwordEditText.editText!!.setText("xxxxxx")

    //Mocking firebase
    val firebaseMock  = mock(FirebaseAuth::class.java)
    // make activity using the mocked class here ---------------
    ServiceLocator.auth = firebaseMock

    onView(withId(R.id.loginBtn)).perform(click())

    // this assertion will pass
    `when`(firebaseMock.signInWithEmailAndPassword("xxxxxxx","xxxxxxx"))
        .thenReturn(notNull())

    firebaseUser = firebaseMock.currentUser!!

    // NOTE: this assertion will fail as the mocked class will always return null and not the actual value
    assertNotNull(firebaseUser)

}
Hussien Fahmy
  • 1,119
  • 6
  • 24
  • Thank you mate , that hepled but one thing regarding the "when"() method , when i put isNull() or either isNotNull() the test passes , i guess in the case of isNull() it should fail ? – Taki Jan 07 '22 at 14:42
  • Mocked classes used to check if a certainethod is called with a certain parameters, it's not a real implementation – Hussien Fahmy Jan 07 '22 at 15:50
  • So it does not interfact with firebase as in real production code ? – Taki Jan 07 '22 at 16:39
  • yes. no implementation, just to check if a certain method called with a certain parameter, Generally to check that a certain action WILL HAPPEN in the future, check this answer https://stackoverflow.com/a/38260/15262615 – Hussien Fahmy Jan 07 '22 at 21:27
  • Your answer is appreciated mate , one last thing please , can you refer me to any link on how to mock the listener for example like database listener ( ValueEventListener()) , since i'm getting data from firebase and i listeners for changes . Thank you , this is the link to my post https://stackoverflow.com/questions/70624912/mock-a-database-reference-callback-with-mockito – Taki Jan 07 '22 at 21:34