Java Mockito失败的原因是;论点不同;但调试器的表现不同

Java Mockito失败的原因是;论点不同;但调试器的表现不同,java,mockito,Java,Mockito,我正在测试一个方法,它使用Mockito模拟对象。当我运行测试时,Mockito告诉我传入参数的参数与预期的不同。如果我在测试的方法中设置了断点,那么调用它的参数实际上就是我所期望的。此方法只被调用一次。为什么Mockito报告的内容与我在调试器中看到的有所不同,我如何修复这个问题 以下是测试: @Test public void addExclusivePermutationsTest() { Permutation p1 = mock(Permutation.class);

我正在测试一个方法,它使用Mockito模拟对象。当我运行测试时,Mockito告诉我传入参数的参数与预期的不同。如果我在测试的方法中设置了断点,那么调用它的参数实际上就是我所期望的。此方法只被调用一次。为什么Mockito报告的内容与我在调试器中看到的有所不同,我如何修复这个问题

以下是测试:

@Test
public void addExclusivePermutationsTest() {
    Permutation p1 = mock(Permutation.class);

    PermutationBuilder pb = new PermutationBuilder();

    when(p1.applyPermutations(anySetOf(String.class)))
            .thenReturn(Collections.singleton("abc123"));

    pb.addExclusivePermutations(p1);
    pb.permute("test");

    verify(p1).applyPermutations(new HashSet<>(
            Collections.singletonList("test")));
}
上述方法在
permute(“test”)
内部调用。字符串
“test”
被转换为
集合
,并传递到上述方法中。上面的方法在
p1
上调用
applyPermutations
。当我使用调试器查看此方法时,
stringPermutations
只包含
[test]
,正如我所期望的那样,并直接传递到
p1
。然后
p1
返回
[abc123]
,因为它是模拟的,上面的方法将它与
stringPermutations
结合起来,以返回
[test,abc123]
。因此出于某种原因,Mockito说
stringPermutations
不是调试器显示的
[test]
,而是方法返回的结果

最后,这里是错误:

Argument(s) are different! Wanted:
permutation.applyPermutations(
    [test]
);
-> at PermutationBuilderTest$AddExclusivePermutationTests.addExclusivePermutationsTest(PermutationBuilderTest.java:87)
Actual invocation has different arguments:
permutation.applyPermutations(
    [abc123, test]
);
最后一个提示(对于仍在阅读的读者)。如果我通过复制
ExclusivePermutation.applyPermutation()
并将其直接放入
PermutationBuilder
中来绕过
ExclusivePermutation
,则测试通过。这是一个谜

编辑:

所以我把范围缩小了一点。在
PermutationBuilder
中,我有以下方法:

public Set<String> permute(String s) {
    for (Modifier modifier : modifierList) {
        s = modifier.applyModification(s);
    }

    Set<String> stringPermutations = new HashSet<>(Collections.singletonList(s));

    for (Permutation permutation : permutationList) {
        Set<String> result = permutation.applyPermutations(stringPermutations);
        stringPermutations.addAll(result);
    }

    return stringPermutations;
}
公共集置换(字符串s){
用于(修改器:修改器列表){
s=修饰符。应用修改;
}
Set stringPermutations=新哈希集(Collections.singletonList);
for(置换置换:置换列表){
集合结果=置换。applyPermutations(stringPermutations);
stringPermutations.addAll(结果);
}
返回字符串置换;
}
分配完结果后,Mockito说该方法是通过
[test]
调用的。但是,当我跳到下一行将其添加到
stringPermutations
时,它将更改为
[abc123,test]
。您可以在下面的两个屏幕截图中看到这一点(查看
参数
数组底部):


问题在于您正在修改用作参数的集合

也就是说,在代码中

Set<String> stringPermutations = new HashSet<>(Collections.singletonList(s));

for (Permutation permutation : permutationList) {
    Set<String> result = permutation.applyPermutations(stringPermutations);
    stringPermutations.addAll(result);
}

如果您确实需要
stringPermutations
来包含这两个元素。

mockito github中针对同一问题有两个问题:

<> >,首先,创建者认为它是一个框架的限制,因为在调用时复制参数会影响性能,无论如何,没有一种通用的方法来做深拷贝。 其次,上面的语句解释了在这种情况下应该做什么:您需要自己克隆参数。我没有尝试过,但以下是建议的方法:

  • org.mockito.internal.stubing.answers.ClonesArguments
  • 在doAnswer中进行手动复制,并代替captor进行验证
但是,当我在用例中使用ClonesArguments时:

doAnswer((invocation) -> {
    new ClonesArguments().answer(invocation);
    // in my case situation is different and instead of modifying invocation
    // my argument is the same collection 4 times with different elements
    // in your case it may or may not work
    // maybe you will have to copy paste and update their code
    return myAnswer;
})

我在debug中看到我的集合的元素被复制,但在验证阶段我仍然只看到最新的值,因此对我来说不起作用。

您是否尝试了
verify(p1).applyPermutations(Mockito.eq(新的HashSet(Collections.singletonList(“test”))?@RahulSharma我已经试过了,但正如我所预料的那样,它没有帮助。问题不是这些集合包含相同的元素,而是它们的计算结果不相等。问题是Mockito说这些集合包含不同的元素,但调试器却不这么说,我需要弄清楚为什么会发生这种情况。你说得对!太棒了,我完全被难住了。谢谢虽然这是正确的,并解释了发生了什么,但为相同的单元测试和模拟更改生产代码没有多大意义。是否有任何解决方案可以通过复制传入对象来捕获?
Set<String> stringPermutations = new HashSet<>();

for (Permutation permutation : permutationList) {
    Set<String> result = permutation.applyPermutations(Collections.singletonList(s));
    stringPermutations.addAll(result);
}

stringPermutations.addAll(Collections.singletonList(s));
doAnswer((invocation) -> {
    new ClonesArguments().answer(invocation);
    // in my case situation is different and instead of modifying invocation
    // my argument is the same collection 4 times with different elements
    // in your case it may or may not work
    // maybe you will have to copy paste and update their code
    return myAnswer;
})