问题描述
我有一个测试代码块,尝试在一般情况下在后续调用中返回两个值,但在特定情况下仅返回与该情况相关的值.该代码看起来像:
I've got a block of test code that is attempting to, in the generic case return two values on subsequent calls, but in specific cases only return the value associated with that case. The code looks something like:
when(mockObject.method(anyString())).thenReturn(string1, string2);
when(mockObject.method(eq("expectedInput1"))).thenReturn(string1);
when(mockObject.method(eq("expectedInput2"))).thenReturn(string2);
预期的行为是,分别调用mockObject.method("foo")
和mockObject.method("bar")
时应分别返回string1
和string2
,但是测试实际上看到了string2
的两个响应.这是Mockito
中的错误吗?还是我误解了Mockito
模式匹配.
The expected behavior is that when calling mockObject.method("foo")
and mockObject.method("bar")
, string1
and string2
should be returned respectively, but the test is actually seeing two responses of string2
. Is this a bug in Mockito
? Or am I misunderstanding Mockito
pattern matching.
我的假设是要匹配的最后一个模式是返回的内容,但是在执行该过程时,Mockito
是否会分别处理第一个thenReturn
块中的每个参数?有什么办法可以解决这个问题?
My assumption was that the last pattern to match is what is returned, but when going through that process does Mockito
treat each argument in the first thenReturn
block separately? Is there any way to get around this behavior?
当我注释掉第二个when调用时,模拟行为的行为符合预期,因此我假设重叠匹配器行为有一些特定之处.
When I comment out the second two when calls, the mocks behave as expected, so I'm assuming there is something specific about the overlapping matcher behavior.
这是Mockito
版本1.9.5
推荐答案
我今天遇到了这个问题.这是由于调用模拟程序来建立存根而实际上消耗了已经存在的存根.
I had this problem today. It is caused by calls to the mock to set up stubbing actually consuming the stubbing already in place.
在此示例中,将第一行更改为
In this example, change the first line to
when(mock.call(anyString())).thenReturn("","",string1,string2)
设置其他模拟返回时,这将给您两个空白响应,而将string1作为第一个有用的返回值.
This will give you two blank responses when you set up your other mock returns, leaving string1 as the first useful return value.
请尝试我认为可能没有这些问题的doReturn替代方法:
Try also the doReturn alternative which I think may not have these issues:
doReturn(string1,string2).when(mock).call(anyString());
这在设置过程中使用存根的方式有所不同.
This uses the stub differently during setup.
因此,我对此进行了更多研究.根据OP的问题,这是我正在使用的功能:
So I did some more research on this. Here's the function I was playing with, based on the OP's question:
Function<String, String> function = mock(Function.class);
when(function.apply(anyString())).thenReturn("A","B","C");
when(function.apply("Jim")).thenReturn("Jim");
when(function.apply("Bob")).thenReturn("Bob");
assertThat(function.apply("Jim")).isEqualTo("Jim");
assertThat(function.apply("Bob")).isEqualTo("Bob");
assertThat(function.apply("")).isEqualTo("A");
assertThat(function.apply("")).isEqualTo("B");
assertThat(function.apply("")).isEqualTo("C");
assertThat(function.apply("")).isEqualTo("C");
上面的操作在isEqualTo("A")
处失败,因为这两个调用Jim
和Bob
的模拟程序的调用消耗了提供给anyString()
的列表中的返回值.
The above fails at isEqualTo("A")
because the two calls to set up the mocks for Jim
and Bob
consume return values from the list provided to anyString()
.
您可能会想对when
子句重新排序,但这失败了,因为anyString()
取代了特殊情况,所以也失败了.
You might be tempted to reorder the when
clauses, but that fails, because the anyString()
supersedes the special cases, so that fails too.
上述DOES的以下版本按预期工作:
The following version of the above DOES work as expected:
when(function.apply(anyString())).thenReturn("A","B","C");
doReturn("Jim")
.when(function)
.apply("Jim");
doReturn("Bob")
.when(function)
.apply("Bob");
assertThat(function.apply("Jim")).isEqualTo("Jim");
assertThat(function.apply("Bob")).isEqualTo("Bob");
assertThat(function.apply("")).isEqualTo("A");
assertThat(function.apply("")).isEqualTo("B");
assertThat(function.apply("")).isEqualTo("C");
assertThat(function.apply("")).isEqualTo("C");
这是因为doReturn
技术旨在修改飞行中已存在的模拟,实际上并不涉及调用模拟中的方法来建立模拟.
This is because the doReturn
technique, which is intended for modifying pre-existing mocks in flight, doesn't actually involve calling the method on the mock to set up the mocking.
您可以使用doReturn
进行所有设置,而不是在when
... thenReturn
和doReturn
.. when
.. function()
之间混合使用.碰巧的是,这有点丑陋:
You could use doReturn
for all setup, rather than mixing between when
...thenReturn
and doReturn
..when
..function()
. As it happens, that's a bit uglier:
doReturn("A").doReturn("B").doReturn("C")
.when(function)
.apply(anyString());
没有方便的varargs
函数来让您依次指定多个收益.上面的代码已经过测试,并且可以正常工作.
There's no convenient varargs
function to let you specify multiple returns in sequence. The above has been tested and does work, though.
这篇关于Mockito如何处理thenReturn块中具有多个参数的重叠匹配器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!