如何测试使用回调的函数?

How to test a function that uses a callback?

假设我们有一个回调函数的接口:

public interface Model {
    interface UserListener {
        void callback(User user);
    }

    void getUser(String username, UserListener listener);
}

并且我们有一个调用作为参数给出的回调的方法:

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

我希望按照以下方式对其进行测试:

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
...

现在,问题是:在这种情况下,如何测试 (Mockito) 调用了 loginFailed() 和 loginSuccess() 的视图?

在 Mockito 中,当模拟调用需要做的不仅仅是 return 一个值时,您可以使用 Answer

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