How can I verify a method is run in a mocked class's callback?

爱⌒轻易说出口 提交于 2019-12-22 18:46:15

问题


I have a utility class in my Android code that handles the authentication of users. I'm writing unit tests for this class with Mokcito to verify that a listener is being notified if the creation of a new user had succeeded or failed. Here is one of this utility class's methods:

public void createNewUser(String email, String password) {
    firebaseAuth.createUserWithEmailAndPassword(email, password)
            .addOnSuccessListener(authResult -> {
                authListener.newUserCreated();
            })
            .addOnFailureListener(e -> {
                authListener.failedCreatingNewUser();
            });
}

I am mocking FirebaseAuth and I want to verify that authListener.newUserCreated() has been called. I have tried using deep stubs and argument captors to handle the chained method calls on firebaseAuth.createUserWithEmailAndPassword but I can't figure out how to get this working.

UPDATE

Here is my test class with the test for this method:

public class AuthUtilsTest {

    private static final String USERNAME = "USERNAME";
    private static final String PASSWORD = "PASSWORD";

    @Mock
    private FirebaseAuth firebaseAuth;

    @Mock
    private FirebaseFirestore firebaseFirestore;

    @Mock
    private BaseEncoding base64;

    @Mock
    private PreferencesRepo preferencesRepo;

    @Mock
    private AuthUtilsContract.EventListener eventListener;

    private AuthUtils authUtils;

    @Before
    public void setupAuthUtils() {
        MockitoAnnotations.initMocks(this);

        authUtils = new AuthUtils(
                preferencesRepo,
                firebaseAuth,
                firebaseFirestore,
                base64
        );

        authUtils.takeEventListener(eventListener);
    }

    @Test
    public void failureCreatingNewUserTellsListener() {
        Task<AuthResult> failedTask = Tasks.forException(new Exception("fail"));
        when(firebaseAuth.createUserWithEmailAndPassword(anyString(), anyString())).thenReturn(failedTask);

        authUtils.createNewUser(USERNAME, PASSWORD);

        verify(eventListener).failedCreatingNewUser();
    }

}

which throws the exception

java.lang.ExceptionInInitializerError at com.google.android.gms.tasks.zzn.addOnSuccessListener(Unknown Source) ... Caused by: java.lang.RuntimeException: Method getMainLooper in android.os.Looper not mocked.


回答1:


Use Mockito.when to make the createUserCall return a mocked Task. Then Mockito.verify on the task to capture the arguments to the add listener call.

Test the captured arguments to the extent you heart desires (this is like a unit test within a unit test, the captured arguments are your new Classes under test).

This method won't actually test that the listeners are called. Just that the add listener method was called and that the callbacks do what they should when called

verify(mockTask).addOnSuccessListener(listenerCaptor.capture());
OnSuccessListener<Auth> newObjectUnderTest = listenerCaptor.getValue();

//ACT
newObjectUnderTest.onSuccess(auth);

//ASSERT
verify(authListener).newUserCreated();



回答2:


Use Mockito.when to make the createUserCall return an already completed Task<AuthResult>.

Then Mockito.verify that the authListener did what it should assuming authListener is also a mock



来源:https://stackoverflow.com/questions/48308609/how-can-i-verify-a-method-is-run-in-a-mocked-classs-callback

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!