问题
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