如何使用 Mockito 模拟 forEach 行为

fee*_*kie 6 java mocking mockito

我想做以下工作,但我不知道如何正确模拟 forEach 行为。(该代码取自一个相关问题Testing Java Enhanced for behavior with Mockito

@Test
public void aa() {
  Collection<String> fruits;
  Iterator<String> fruitIterator;

  fruitIterator = mock(Iterator.class);
  when(fruitIterator.hasNext()).thenReturn(true, true, true, false);
  when(fruitIterator.next()).thenReturn("Apple")
      .thenReturn("Banana").thenReturn("Pear");

  fruits = mock(Collection.class);
  when(fruits.iterator()).thenReturn(fruitIterator);
  doCallRealMethod().when(fruits).forEach(any(Consumer.class));

  // this doesn't work (it doesn't print anything)
  fruits.forEach(f -> {
    mockObject.someMethod(f); 
  });

  // this works fine
  /*
  int iterations = 0;
  for (String fruit : fruits) {
    mockObject.someMethod(f); 
  }
  */

  // I want to verify something like this
  verify(mockObject, times(3)).someMethod(anyString());
}
Run Code Online (Sandbox Code Playgroud)

任何帮助将不胜感激。

Ale*_*iez 7

该方法forEach的的Collection接口是一个“后卫”方法; 它不使用Iterator而是调用Consumer传递给方法的。

如果您使用的版本的Mockito 2+(*),你可以问的默认方法forEach中的Collection接口被称为:

Mockito.doCallRealMethod().when(fruits).forEach(Mockito.any(Consumer.class));
Run Code Online (Sandbox Code Playgroud)

请注意,“防御者”方法实际上会请求Iterator遍历集合,因此将使用Iterator您在测试中模拟的 。如果Iterator模拟集合没有提供它,它就不会工作,就像when(fruits.iterator()).thenReturn(fruitIterator)

(*):自版本 2 起,Mockito 增加了支持 Java 8 默认(“防御者”)方法的可能性 - 您可以在此处查看跟踪问题。


pat*_*io2 5

Iterator mockIterator = mock(Iterator.class);
doCallRealMethod().when(fruits).forEach(any(Consumer.class));
when(fruits.iterator()).thenReturn(mockIterator);
when(mockIterator.hasNext()).thenReturn(true, false);
when(mockIterator.next()).thenReturn(mockObject);
Run Code Online (Sandbox Code Playgroud)