使用Mockito测试Java增强的行为
我想使用Mockito测试一个java方法,该方法上有一个增强的for。问题是,当我不知道如何设定对增强型工作的期望时。以下代码来自:使用Mockito测试Java增强的行为,java,unit-testing,for-loop,mockito,Java,Unit Testing,For Loop,Mockito,我想使用Mockito测试一个java方法,该方法上有一个增强的for。问题是,当我不知道如何设定对增强型工作的期望时。以下代码来自: 导入静态org.mockito.mockito.when; 导入静态org.testng.Assert.assertTrue; 导入java.util.ArrayList; 导入java.util.Iterator; 导入java.util.List; 导入org.mockito.mockito; 导入org.testng.annotations.Test; 公
导入静态org.mockito.mockito.when;
导入静态org.testng.Assert.assertTrue;
导入java.util.ArrayList;
导入java.util.Iterator;
导入java.util.List;
导入org.mockito.mockito;
导入org.testng.annotations.Test;
公共类列表测试
{
@试验
公开无效测试()
{
List mockList=Mockito.mock(List.class);
迭代器mockIterator=Mockito.mock(迭代器.class);
when(mockList.iterator()).thenReturn(mockIter);
when(mokiter.hasNext()).thenReturn(true).thenReturn(false);
when(mokiter.next())。然后返回(“A”);
布尔标志=假;
用于(字符串s:模拟列表){
flag=true;
}
资产真实性(标志);
}
}
for循环中的代码永远不会执行。为迭代器设置期望值不起作用,因为java增强版for在内部不使用列表迭代器。设置List.get()
方法的期望值也不起作用,因为增强型for实现似乎也没有调用List的get()
方法
任何帮助都将不胜感激。除非我遗漏了什么,否则您可能应该返回一个真实的模拟值列表。在本例中,在生成器方法中构造测试字符串列表,并简单地返回该列表。在更复杂的情况下,可以使用模拟对象替换列表的内容
最后,我无法想象为什么您真的需要模拟一个增强的for循环。单元测试的性质不适合这种级别的检查。这仍然是一个有趣的问题 模仿迭代器对我很有用。请参见下面的代码示例:
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<String> fruits;
private Iterator<String> 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);
}
}
导入静态org.junit.Assert.assertEquals;
导入静态org.mockito.mockito.mock;
导入静态org.mockito.mockito.when;
导入java.util.Collection;
导入java.util.Iterator;
导入org.junit.Before;
导入org.junit.Test;
公共类TestMockEditor{
私人收藏水果;
私有迭代器;
@抑制警告(“未选中”)
@以前
公共作废设置(){
水果迭代器=mock(迭代器类);
when(fruitIterator.hasNext())。然后返回(true、true、true、false);
when(fruitIterator.next()).thenReturn(“苹果”)
然后返回(“香蕉”)。然后返回(“梨”);
水果=模拟(Collection.class);
when(fruits.iterator())。然后返回(fruitIterator);
}
@试验
公开无效测试(){
int迭代次数=0;
用于(串水果:水果){
迭代++;
}
资产质量(3,迭代);
}
}
我只想指出一点,因为我整天都在为此而挣扎:
如果要使用myList.forEach(…)
语法而不是(:)的,则必须包括(设置模拟列表的位置):
你想做这样的事
/**
* THe mock you want to make iterable
*/
@Mock
javax.inject.Instance<Integer> 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<Integer> 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<Iterator<Integer>>() {
@Override
public Iterator<Integer> answer(InvocationOnMock invocation)
throws Throwable {
return iterator;
}
}).when(myMockedInstanceObject).iterator();
}
/**
*你想让它变得易懂的模拟
*/
@嘲弄
javax.inject.Instance myMockedInstanceObject;
/**
*将myMockedInstanceObject mock设置为在业务逻辑
*要循环iterable上的现有实例。。。。
*/
私有void setupTransportOrderToTransportEquipmentMapperInstancesToBeiteratable()的设置{
//(a)创建一个非常真实的迭代器对象
最终迭代器迭代器=数组
.asList(Integer.valueOf(1),Integer.valueOf(2)).iterator();
//(b)确保循环时模拟返回正确的迭代器
Mockito.doAnswer(新答案(){
@凌驾
公共迭代器应答(调用锁调用)
扔掉的{
返回迭代器;
}
}).when(myMockedInstanceObject).iterator();
}
coments和javadoc行应该清楚地说明如何模拟任何iterable的行为,而不管它是一个列表、一个集合、一个javax.inject.instance或其他任何东西。。我知道它可以通过创建模拟列表进行测试。我只是想知道增强的for循环在做什么,因为它在任何时候都不使用迭代器或调用列表的get()方法。那么它如何访问数据结构呢?有意思吧?我也试过执行你的代码。一旦我将'mockIterator'变量重命名为'mockIter',测试就通过了。在你的例子中,你知道项目的确切数量,因此你可以模拟'hasNext()`,如果你在for循环中创建这些项目,而你事先不知道对象的数量呢?以上问题有答案吗?如果我们不知道迭代次数呢?如果你不知道迭代次数(在单元测试中有点奇怪),那么这项技术就不能应用。anyObject()
现在不推荐使用,你可以使用:doCallRealMethod().when(myMockedList).forEach(any())代码>
doCallRealMethod().when(myMockedList).forEach(anyObject());
/**
* THe mock you want to make iterable
*/
@Mock
javax.inject.Instance<Integer> 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<Integer> 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<Iterator<Integer>>() {
@Override
public Iterator<Integer> answer(InvocationOnMock invocation)
throws Throwable {
return iterator;
}
}).when(myMockedInstanceObject).iterator();
}