如何使用Mockito处理“任何其他价值”?

2022-09-01 03:10:48

我有一个接口,我想用Mockito来模拟它。我希望如果我传入 ,则 mocked 方法返回,但所有其他值将引发异常。我可以这样做吗?Fooint Foo.bar(int)991

final Foo foo = mock(Foo.class);
when(foo.bar(1)).thenReturn(99);
when(foo.bar(anyInt())).thenThrow(new IllegalArgumentException());

换句话说,会优先于 ?我不希望它为 .文档说,对于多个定义,最后一个定义更重要,但我无法判断这是否意味着相同的参数。如果它适用于这里,我是否需要先定义通配符?或者这两者甚至有任何关系,因为其中一个是匹配器,另一个只是一个值?1anyInt()1anyInt()


答案 1

您有两种选择:匹配“除一个以外的任何值”和覆盖存根。(我想你也可以对复杂的自定义行为使用答案,但对于这种情况来说,这太过分了。

对除给定值以外的任何值进行存根

Mockito的AddramyMatchers类提供了许多有用的匹配器,包括诸如not之类的运算符。这将允许您为除特定值(或表达式)之外的所有值设置行为。

when(foo.bar(1)).thenReturn(99);
when(foo.bar(not(eq(1)))).thenThrow(new IllegalArgumentException());

请注意,由于 Mockito 的参数匹配器堆栈,运算符必须与匹配器一起使用,而不是值,这可能需要作为显式匹配器Matchers.eqequals

/* BAD */  when(foo.bar(not(  1  ))).thenThrow(new IllegalArgumentException());
/* GOOD */ when(foo.bar(not(eq(1)))).thenThrow(new IllegalArgumentException());

覆盖存根

对于存根,最后定义的匹配链获胜。这允许您在方法中设置常规测试夹具行为,并根据需要在单个测试用例中覆盖它,但也意味着顺序在存根调用中很重要。@Before

when(foo.baz(anyInt())).thenReturn("A", "B");  /* or .thenReturn("A").thenReturn("B"); */
when(foo.baz(9)).thenReturn("X", "Y");

foo.baz(6); /* "A" because anyInt() is the last-defined chain */
foo.baz(7); /* "B" as the next return value of the first chain */
foo.baz(8); /* "B" as Mockito repeats the final chain action forever */

foo.baz(9); /* "X" because the second chain matches for the value 9 */
foo.baz(9); /* "Y" forever because the second chain action still matches */

因此,您永远不应该按照问题中列出的顺序看到两个存根,因为如果一般匹配紧跟在特定匹配之后,那么该特定匹配项将永远不会被使用(并且可能被删除)。

请注意,有时需要将语法更改为覆盖间谍或危险的存根行为时。Mockito 知道不要计算对验证或沿链前进的调用,但异常仍然可能导致测试失败。doAnswerwhenthenVerb

/* BAD: the call to foo.bar(1) will throw before Mockito has a chance to stub it! */
when(foo.bar(anyInt())).thenThrow(new IllegalArgumentException());
when(foo.bar(1)).thenReturn(99);

/* GOOD: Mockito has a chance to deactivate behavior during stubbing. */
when(foo.bar(anyInt())).thenThrow(new IllegalArgumentException());
doReturn(99).when(foo).bar(1);

答案 2

推荐