Issue
Suppose we have an interface for a callback function as such:
public interface Model {
interface UserListener {
void callback(User user);
}
void getUser(String username, UserListener listener);
}
And we have a method that calls a callback that was given as an argument:
public class Presenter() {
...
public Presenter(Model model, View view) {
this.model = model;
this.view = view;
}
public void checkLogin() {
String username = view.getUsername();
String password = view.getPassword();
model.getUser(username, user -> {
if (user == null) {
view.loginFailed();
} else {
view.loginSuccess(user.getName());
}
});
}
}
I am hoping to test it along the lines of:
when(view.getUsername()).thenReturn("abc");
when(view.getPassword()).thenReturn("xyz");
Presenter presenter = new Presenter(view, model);
presenter.checkLogin();
// How do I verify that view.loginFailed() or view.loginSuccess() is called here
...
Now, to the question: Given this kind of scenario, how would one test (Mockito) the view having loginFailed() and loginSuccess() called?
Solution
In Mockito you can use an Answer
when a call on a mock needs to do more than just return a value:
@ExtendWith(MockitoExtension.class)
public class MockEg {
public interface Model {
interface UserListener {
void callback(User user);
}
void getUser(String username, UserListener listener);
}
interface User {}
@Test
public void aTest() {
Model model = mock(Model.class);
User user = mock(User.class);
doAnswer(new Answer<Void>() {
@Override
public Void answer(InvocationOnMock invocation) throws Throwable {
Model.UserListener listener = invocation.getArgument(1);
listener.callback(user);
return null;
}
}).when(model).getUser(any(), any());
...
}
}
Answered By - tgdavies
Answer Checked By - Senaida (JavaFixing Volunteer)