Mockito 验证特定的 lambda 是否已作为参数传递给 mock 的方法

2022-09-01 03:53:55

我想测试以下方法:

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

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

}

where 是一个帮助器类,它将以 lambda 的形式接受功能接口实现,并将其存储以供以后执行。MessageHandler

有没有办法用 mockito 验证 mocked 的方法是否已经使用特定的 lambda 表达式调用:dispatchMessageMessageHandler

意思是,我可以写这样一个测试吗:

        @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$28/379645464@48f278eb

实际调用有不同的参数:

..........Lambda$27/482052083@2f217633

这是有道理的,因为mockito试图比较功能接口的两个不同实现,它们具有不同的哈希代码。

那么有没有其他方法来验证该方法是否已被调用,该lambda返回void并具有body方法?dispatchMessage()dispatcher.dispatch("activityId", "ctxId", 1l,);


答案 1

是的,可以。这里的诀窍是,您必须访问传递给 的 lambda 的实例,然后执行该表达式,然后才能验证结果。registerMessage

为了获得一个有意义的示例,我创建了这个类,其中包含要测试的:HandlerdispatchMessage

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

您必须记住的是,lambda 表达式只是将函数传递给方法的简写形式。在此示例中,函数是 .因此,接口的方法采用 a as 它的参数。我还包含了 的实现,它是从内部调用的。对此的测试如下所示:runRunnableregisterMessageMessageHandlerRunnableDispatcherregisterMessage

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

有一个 for lambda 表达式,我们在 第一次验证 .验证后,我们可以从捕获器中检索 lambda 表达式。lambda 表达式的类型是 接口中定义的 。因此,我们可以在其上调用该方法,然后验证是否使用所有适当的参数调用了 上的方法。ArgumentCaptorregisterMessageRunnableMessageHandlerrundispatchDispatcher


答案 2

在特定的 lambda 之外,您可以验证您的方法是否使用任何 lambda 表达式调用,如下所示:

    verify(handler).registerMessage(any())

    private fun <T> any(): T {
        Mockito.any<T>()
        return null as T
    }

推荐