java - JMockit - 期望 - 匹配调用包含模拟对象作为参数的方法

标签 java junit mocking jmockit expectations

我正在使用 JMockit 测试应用程序(Java 8、Junit 4.12、JMockit 1.17)。

我有一些代码应该将一些数据上传到端点列表。

实际执行上传到端点的类称为 PlatformDataUploader。此类有一个称为“上传”的方法,可对单个端点执行单个“上传”。此方法采用目的地的名称(这是一个两个字符的字符串,以及要上传的对象)。它根据目标名称构造数据应发送到的 URL。

我想创建一个测试来简单地确认,当应用程序被执行时,PlatformDataUploader 的上传方法被调用了预期的次数(7 次,因为应用程序当前配置为将数据上传到 7 个端点) .我想确认传递给上传方法的目标字符串是预期的字符串,但我不关心发送的数据(由 PlatformInstallationData 实例表示)。

应用程序代码的简化版本如下:

 ...

 private boolean uploadToServices(final List<String> serviceNames) {

    boolean allGood = true;

    PlatformDataUploader platformDataUploader = new PlatformDataUploader();

    for (String serviceName : serviceNames) {

        LOG.info("Attempting to upload to " + serviceName + "...");

        // construct object to send
        PlatformInstallationData platformInstallationData = new PlatformInstallationData();

        ...
        // code here that adds content to platformInstallationData
        ...

        // send object to endpoint of this service
        allGood = allGood &&
            platformDataUploader.upload(serviceName, platformInstallationData);
    }

    return allGood;
}

简化版的测试代码如下:

@Test
public void whenUploadThenExpectedCallsToUploader(@Mocked final PlatformDataUploader platformDataUploader,
        @Mocked final PlatformInstallationData platformInstallationData)
                throws IOException {

    UploaderApplication target = new UploaderApplication();

    new Expectations() {
        {
            platformDataUploader.upload("AP", platformInstallationData);
            result = true;
            times = 1;

            platformDataUploader.upload("VV", platformInstallationData);
            result = true;
            times = 1;
            ...
            THE REST OF THE EXPECTED CALLS 
            ...


        }
    };

    target.execute(params);
}

当我执行测试时,我得到:“mockit.internal.MissingInvocation:缺少 1 次调用”。它指的是我定义的期望中的第一行。

问题似乎是上传方法中的第二个参数(模拟的 PlatformInstallationData)与在应用程序代码中创建的实例不匹配(即使该实例也应该被模拟)。

为了试图理解发生了什么,我做了一个测试,我从上传方法(从应用程序代码和测试代码)中删除了第二个参数,因此它只需要匹配一个字符串,例如“AP"与当时存在于应用程序中的字符串匹配,在这种情况下它匹配正确。所以我知道,使用这种方法,它可以正确匹配字符串,但无法匹配模拟的 PlatformInstallationData 对象。

我对这种行为感到惊讶,因为我确信我以前能够创建包含模拟对象作为方法参数的期望,并且我认为它与它们正确匹配。

任何人都可以解释这种行为,并可能建议应该如何测试这种行为。非常感谢!

最佳答案

我找到了一种编写测试的方法,使其与调用相匹配,并确认对上传方法进行了预期的调用次数,并且将预期的字符串作为第一个参数传递。我为第二个参数使用了“任何”占位符。它有点难看,因为我必须做 Actor 。如下图:

@Test
public void whenUploadThenExpectedCallsToUploader(@Mocked final PlatformDataUploader platformDataUploader,
        @Mocked final PlatformInstallationData platformInstallationData)
                throws IOException {

    InstallPlatformCommand target = new InstallPlatformCommand(Action.INSTALL_PLATFORM);

    new Expectations() {
        {
            platformDataUploader.upload("AP", (PlatformInstallationData) any);
            result = true;
            times = 1;

            platformDataUploader.upload("VV", (PlatformInstallationData) any);
            result = true;
            times = 1;

            ...
            The rest of the expected calls
            ...
        }
    };

    target.execute(params);
}

我相信还有其他方法可以做到这一点。如果您有更清洁的方法,请告诉我。

关于java - JMockit - 期望 - 匹配调用包含模拟对象作为参数的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34186572/

相关文章:

java - 首选项屏幕中的自定义列表首选项对话框布局,带有自定义列表项

java - 我们如何在 JUnit 中模拟 session 值 (request.getSession())?

java - 如何修改 JComponent 的 setBounds 方法?

java - 在 Java 中,方法/构造函数声明可以出现在另一个方法/构造函数声明中吗?

java - 在对 void 方法进行单元测试时,如何确定集合中的元素?

laravel - 如果您在使用 Laravel 的测试环境中,是否有一种默认情况下模拟 API 请求的方法?

c# - 如何模拟 LINQ to Entities 助手,例如 'SqlFunctions.StringConvert()'

mocking - OpenAPI 3.0 模拟生成器

java - 我如何使用我的日期格式 yyyy-mm-dd 在我的选择框中列出月份值

Spring 上下文测试找不到配置位置