JMockit - 期望 - 匹配包含模拟对象作为参数的方法调用
Posted
技术标签:
【中文标题】JMockit - 期望 - 匹配包含模拟对象作为参数的方法调用【英文标题】:JMockit - Expectations - matching invocation of method that includes mocked object as argument 【发布时间】:2015-12-09 18:42:50 【问题描述】:我正在使用 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: Missing 1 invocation”。它指的是我定义的期望中的第一行。
问题似乎是上传方法中的第二个参数,即模拟的 PlatformInstallationData,与应用程序代码中创建的实例不匹配(即使该实例也应该被模拟)。
为了了解发生了什么,我做了一个测试,我从上传方法(从应用程序代码和测试代码)中删除了第二个参数,因此它只需要匹配一个字符串,例如“ AP" 与当时存在于应用程序中的字符串相对应,在这种情况下,它匹配正确。所以我知道,使用这种方法,它可以正确匹配一个字符串,但它无法匹配模拟的 PlatformInstallationData 对象。
我对这种行为感到惊讶,因为我确信我之前能够创建包含模拟对象作为方法参数的期望,并且我认为它正确地匹配了它们。
谁能解释一下这种行为,并可能建议如何测试它。非常感谢!
【问题讨论】:
【参考方案1】:我找到了一种编写测试的方法,使其与调用匹配,并确认对上传方法进行了预期的调用次数,并且预期的字符串作为第一个参数传递。我对第二个参数使用了“任何”占位符。这有点难看,因为我必须做演员。如下图:
@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);
我相信还有其他方法可以做到这一点。如果您有更清洁的方法,请告诉我。
【讨论】:
你可能不需要模拟PlatformInstallationData
,所以我会删除那个模拟参数。 (X) any
的替代方法是使用 withInstanceOf(PlatformInstallationData.class)
。最后,您可以使用withCapture(List<String>)
将传递给“serviceName”参数的值序列捕获到本地列表中,然后使用assertEquals
将其与输入列表进行比较;这将允许测试记录 upload
方法的单个期望。以上是关于JMockit - 期望 - 匹配包含模拟对象作为参数的方法调用的主要内容,如果未能解决你的问题,请参考以下文章
JMockit 期望 API:如何在方法/构造函数调用时抛出异常