为什么我在这里使用 anyInt() 检测到 Mockito 错误放置的参数匹配器?

Why am I getting Mockito misplaced argument matcher detected here with anyInt()?

Mockito.when(metadataDao.getStuff(Mockito.anyInt()).get(Mockito.anyInt()))
               .thenReturn(returnedVariable);

我收到以下错误:

java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
    at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
    at java.util.LinkedList.get(LinkedList.java:476)
    at 

为什么我不能使用匹配器?

Mockito.anyInt() 通过副作用起作用;当它将值传递给真实的 class 时,它实际上发送 0.

看起来 metadataDao.getStuff 正在返回一个大小为 0 的实数 LinkedList。然后,您将 0 发送到那个实数 LinkedList,它调用大小为 0 的真实 get 方法,您会得到预期的正常错误。

你可以通过不在 Mockito 中使用 链式方法调用 来避免这样的问题,换句话说,永远不要这样做:

when(obj.methodOne().methodTwo())

相反,只需使用一个方法调用。在您的示例中,这可能是:

List<MyObj> mockList = Mockito.mock(List.class);
Mockito.when(metadataDao.getStuff(Mockito.anyInt()).thenReturn(mockList);
Mockito.when(mockList.get(Mockito.anyInt())).thenReturn(returnedVariable);

另请注意,正如@JeffBowman 在评论中指出的那样,当真正的 List 可以时,您永远不应该嘲笑 List

虽然 @durron597 的分析是正确的,但有一种方法可以配置 Mockito 来处理您当前的代码,方法是使用 Mockito.RETURNS_DEEP_STUBS 配置您的 mock。这样 getStuff 将自动 return 一个可用于链接的模拟。

在这两种情况下,Mockito 团队都不鼓励这种 "deep" 模拟行为。只是他们布道的摘录(在上面的 link 中找到):

WARNING: This feature should rarely be required for regular clean code! Leave it for legacy code. Mocking a mock to return a mock, to return a mock, (...), to return something meaningful hints at violation of Law of Demeter or mocking a value object (a well known anti-pattern).