Search code examples
javajunitcallbackmockito

How to test a function that uses a callback?


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());
            ...
        }
    }