Mockito убедитесь, что определенная лямбда была передана в качестве аргумента в методе mock

Я хочу проверить следующий метод:

    public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) {

    handler.registerMessage(() -> {
        dispatcher.dispatch(argument1,
                argument2,
                argument3);
    });

}

здесь MessageHandler - вспомогательный класс, который примет функциональную реализацию интерфейса в виде лямбды и сохранит ее для последующего выполнения.

есть ли способ проверить с mockito, что dispatchMessage метод глумились MessageHandler вызывается с определенным лямбда-выражением:

смысл, могу ли я написать такой тест:

        @Test
public void testDispatchMessage_Success() throws Exception {

    myMessageDispatcher.dispatchMessage(handler, "activityId", "ctxId", 1l, );

    verify(handler, times(1)).dispatchMessage(() -> {
        dispatcher
            .dispatch("activityId", "ctxId", 1l,);
    });

}

}

этот тест приведет к утверждению ошибка: Аргумент(ы) бывают разные! Хотел:

......Tests$$Lambda/379645464@48f278eb

фактический вызов имеет разные аргументы:

..........Lambda/482052083@2f217633

что имеет смысл, так как mockito пытается сравнить две разные реализации функционального интерфейса, которые имеют другой хэш-код.

Итак, есть какой-то другой способ проверить, что метод dispatchMessage() был вызван с лямбдой, которая возвращает void и имеет метод тела dispatcher.dispatch("activityId", "ctxId", 1l,); ?

1 ответов


Да, вы можете. Фокус здесь в том, что вы должны добраться до экземпляра лямбды, который передается в registerMessage а затем выполните это выражение, а затем вы можете проверить результат.

С целью значимого примера я создал это Handler класс, содержащий dispatchMessage что вы хотите проверить:

public class Handler {

    private Dispatcher dispatcher = new Dispatcher();

    public void dispatchMessage(MessageHandler handler, String argument1, String argument2, Long argument3) {

        handler.registerMessage(() -> {
            dispatcher.dispatch(argument1,
                    argument2,
                    argument3);
        });

    }

    interface MessageHandler {
        void registerMessage(Runnable run);
    }

    static class Dispatcher {
        void dispatch(String a, String b, long c){
            // Do dispatch
        }
    }
}

вы должны помнить, что лямбда-выражение-это просто короткая форма руки для передачи функции методу. В этом примере функция run метод a Runnable. Поэтому метод registerMessage интерфейс MessageHandler принимает Runnable как аргументом. Я также включил реализацию для Dispatcher, который вызывается из registerMessage. Тест для этого выглядит так:

@RunWith(MockitoJUnitRunner.class)
public class HandlerTest {
    @Mock
    private Dispatcher dispatcher;
    @InjectMocks
    private Handler classUnderTest;
    @Captor
    private ArgumentCaptor<Runnable> registerMessageLambdaCaptor;

    @Test
    public void shouldCallDispatchMethod() {
        final String a = "foo";
        final String b = "bar";
        final long c = 42L;

        MessageHandler handler = mock(MessageHandler.class);

        classUnderTest.dispatchMessage(handler, a, b, c);

        verify(handler).registerMessage(registerMessageLambdaCaptor.capture());

        Runnable lambda = registerMessageLambdaCaptor.getValue();

        lambda.run();

        verify(dispatcher).dispatch(a, b, c);
    }
}

есть ArgumentCaptor для лямбда-выражения, которое мы используем при первой проверке registerMessage. После этой проверки мы можем получить лямбда-выражение от похитителя. Тип лямбда-выражение-это Runnable, как определено в . Следовательно, мы можем назвать run метод на нем, а затем убедитесь, что dispatch метод Dispatcher был вызван со всеми соответствующими аргументами.