我正在使用JMockit来测试一个应用程序(Java 8、Junit 4.12、JMockit 1.17)。
我有一些代码,它应该将一些数据上传到一些端点列表中。
实际上执行上传到终端点的类名为PlatformDataUploader。这个类有一个方法,叫做“upload”,用于执行单个端点的“上传”。此方法接受目标名称(一个由两个字符组成的字符串)和要上传的对象作为参数。根据目的地的名称,它构建应该发送数据的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”错误。它指的是我定义的期望中的第一行。
问题似乎在于upload方法的第二个参数,即模拟的PlatformInstallationData与应用程序代码中创建的实例不匹配(尽管该实例也应该被模拟)。
为了试图理解发生了什么,我进行了一个测试,其中我从upload方法中删除了第二个参数(从应用程序代码和测试代码中),因此它只需要将一个字符串(例如“AP”)与该点中存在的字符串进行匹配,在这种情况下,它确实匹配正确。所以我知道,使用这种方法,它可以正确匹配字符串,但无法匹配模拟的PlatformInstallationData对象。
我对这种行为感到惊讶,因为我确信之前我能够创建包括模拟对象作为方法参数的期望,并且我认为它们会正确匹配。
请问是否有人能够解释这种行为,并可能建议如何进行测试。非常感谢!
PlatformInstallationData
,所以我建议移除那个模拟参数。一个替代(X) any
的方法是使用withInstanceOf(PlatformInstallationData.class)
。最后,你可以通过使用withCapture(List<String>)
将传递给 "serviceName" 参数的值序列捕获到本地列表中,并稍后使用assertEquals
将其与输入列表进行比较;这将允许测试记录对upload
方法的单个期望。 - Rogério