模拟传递给回调(lambdas)的参数

时间:2018-06-26 09:47:07

标签: java mocking mockito jdbi

如何使用Mockito模拟接受lambda的方法,以便能够控制将哪些参数传递给回调?我专门尝试模拟这样使用的JDBI method useExtension

jdbi.useExtension(OrgUnitDao.class, dao -> {
    // Skip if already loaded
    // Skip if already loaded
    if (dao.orgUnitsAreLoaded()) {

我想替换传递回回调的dao对象,以便可以使用dao.orgUnitsAreLoaded()的返回值控制分支。

签名看起来像这样

public <E,X extends Exception> void useExtension(Class<E> extensionType,
                                             ExtensionConsumer<E,X> callback)
                                      throws NoSuchExtensionException,
                                             X extends Exception

2 个答案:

答案 0 :(得分:0)

这是我问题的完整答案。它已简化为如何进行存根的最基础知识,因此也无法反映我要测试的生产代码,但它恰好显示了执行此操作所需的机制。

final Jdbi jdbi = mock(Jdbi.class);
doAnswer(invocation -> {

    System.out.println("this is the doAnswer lambda - just setting up the answer and the mocks");

    final Class<OrgUnitDao> daoClass = invocation.getArgument(0);
    final ExtensionConsumer callback = invocation.getArgument(1);
    final OrgUnitDao mock1 = mock(daoClass);

    when(mock1.orgUnitsAreLoaded()).thenReturn(false);

    // call the actual callback method
    callback.useExtension(mock1);

    return null;

}).when(jdbi).useExtension(eq(OrgUnitDao.class), any());

// This is the method call I am to test
// Regard this as hidden away in some outer method in
// the System-Under-Test, but that I have been able
// to inject all its dependencies
jdbi.useExtension(OrgUnitDao.class, new Foo());

/// Further down, outside of the method

// Only replaced the lambda with this to get toString() for debugging ...
class Foo implements ExtensionConsumer<OrgUnitDao, RuntimeException> {
    @Override
    public void useExtension(OrgUnitDao orgUnitDao) throws RuntimeException {
        System.out.println("A real method call, now using the passed in mocked dao:" + orgUnitDao.orgUnitsAreLoaded());
    }

    @Override
    public String toString() {
        return "OrgUnitDao class";
    }
}

答案 1 :(得分:0)

为使问题"Calling callbacks with Mockito"上的对话并行进行,您的lambda可能在被测方法的执行期间被同步调用,或者稍后可能由于某些外部因素或交互而被调用。像Dawood's answer there一样,your answer here也可以使用Mockito答案,并且是寻找同步样式的唯一方法(mockJdbi在{{1}之前立即调用lambda }返回)。如果您要异步调用lambda,或者您的系统允许您异步调用lambda,则可能要在被测方法返回后测试状态,但在交互之前请测试与lambda

methodUnderTest

尽管lambda减少了以前与匿名内部类相关联的样板,但您也可能更喜欢使用Captor样式,因为它可以避免创建冗长的Answer实现并在其中隐藏测试断言或Mockito验证。如果您的项目偏向于具有清晰的“先给定时”结构的BDD风格的模拟程序,这尤其诱人(尽管我的示例更类似于“先给定时后给定”)。