使用Mockito测试Java增强的行为

我想测试一个使用Mockito对其进行增强的java方法。 问题是,当我不知道如何设置增强的期望为工作。 以下代码来自mockito google组中未解决的问题 :

import static org.mockito.Mockito.when; import static org.testng.Assert.assertTrue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.mockito.Mockito; import org.testng.annotations.Test; public class ListTest { @Test public void test() { List mockList = Mockito.mock(List.class); Iterator mockIterator = Mockito.mock(Iterator.class); when(mockList.iterator()).thenReturn(mockIter); when(mockIter.hasNext()).thenReturn(true).thenReturn(false); when(mockIter.next()).thenReturn("A"); boolean flag = false; for(String s : mockList) { flag = true; } assertTrue(flag); } } 

for循环中的代码永远不会被执行。 设置迭代器的期望不起作用,因为java增强的内部不使用列表迭代器。 设置对List.get()方法的期望也不是因为实现的增强似乎也没有调用列表的get()方法。

任何帮助都感激不尽。

嘲弄迭代器对我有用。 见下面的代码示例:

 import static org.junit.Assert.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.util.Collection; import java.util.Iterator; import org.junit.Before; import org.junit.Test; public class TestMockedIterator { private Collection fruits; private Iterator fruitIterator; @SuppressWarnings("unchecked") @Before public void setUp() { 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); } @Test public void test() { int iterations = 0; for (String fruit : fruits) { iterations++; } assertEquals(3, iterations); } } 

除非我遗漏了某些东西,否则你应该返回一个真实的模拟值列表。 在这种情况下,在生成器方法中构造测试字符串列表并简单地返回它。 在更复杂的情况下,您可以使用模拟对象替换列表的内容。

作为结束点,我无法想象为什么你真的需要模拟增强的for循环。 unit testing的性质不适合该级别的检查。 这是一个有趣的问题。

只是想指出一些事情,因为我整天都在苦苦思索:

如果要使用myList.forEach(...)语法而不是for(:) ,则必须包含(设置模拟列表的位置):

 doCallRealMethod().when(myMockedList).forEach(anyObject()); 

你想做这样的事情。

 /** * THe mock you want to make iterable */ @Mock javax.inject.Instance myMockedInstanceObject; /** * Setup the myMockedInstanceObject mock to be iterable when the business logic * wants to loop existing instances of the on the iterable.... */ private void setupTransportOrderToTransportEquipmentMapperInstancesToBeIteratble() { // (a) create a very real iterator object final Iterator iterator = Arrays .asList(Integer.valueOf(1), Integer.valueOf(2)).iterator(); // (b) make sure your mock when looped over returns a proper iterator Mockito.doAnswer(new Answer>() { @Override public Iterator answer(InvocationOnMock invocation) throws Throwable { return iterator; } }).when(myMockedInstanceObject).iterator(); } 

行coments和javadoc应该足够清楚如何模拟任何iterable的行为,无论它是一个列表,一个集合javax.inject.instance或其他什么。