Java 通过 mockito 创建一个模拟列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18514033/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 08:42:24  来源:igfitidea点击:

Create a mocked list by mockito

javaunit-testingjunitmockingmockito

提问by Tien Nguyen

I want to create a mocked list to test below code:

我想创建一个模拟列表来测试以下代码:

 for (String history : list) {
        //code here
    }

Here is my implementation:

这是我的实现:

public static List<String> createList(List<String> mockedList) {

    List<String> list = mock(List.class);
    Iterator<String> iterHistory = mock(Iterator.class);

    OngoingStubbing<Boolean> osBoolean = when(iterHistory.hasNext());
    OngoingStubbing<String> osHistory = when(iterHistory.next());

    for (String history : mockedList) {

        osBoolean = osBoolean.thenReturn(true);
        osHistory = osHistory.thenReturn(history);
    }
    osBoolean = osBoolean.thenReturn(false);

    when(list.iterator()).thenReturn(iterHistory);

    return list;
}

But when the test run it throw exception at line:

但是当测试运行时,它会在以下行抛出异常:

OngoingStubbing<DyActionHistory> osHistory = when(iterHistory.next());

for details:

详情:

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
-> at org.powermock.api.mockito.PowerMockito.when(PowerMockito.java:495)

E.g. thenReturn() may be missing.
Examples of correct stubbing:
    when(mock.isOk()).thenReturn(true);
    when(mock.isOk()).thenThrow(exception);
    doThrow(exception).when(mock).someVoidMethod();
Hints:
 1. missing thenReturn()
 2. you are trying to stub a final method, you naughty developer!

How can i fix it ? Thanks

我该如何解决?谢谢

采纳答案by Dawood ibn Kareem

OK, this is a bad thing to be doing. Don't mock a list; instead, mock the individual objects inside the list. See Mockito: mocking an arraylist that will be looped in a for loopfor how to do this.

好吧,这是一件坏事。不要嘲笑列表;相反,模拟列表中的单个对象。请参阅Mockito:模拟将在 for 循环中循环的数组列表以了解如何执行此操作。

Also, why are you using PowerMock? You don't seem to be doing anything that requires PowerMock.

另外,你为什么使用PowerMock?您似乎没有做任何需要 PowerMock 的事情。

But the real cause of your problem is that you are using whenon two different objects, before you complete the stubbing. When you call when, and provide the method call that you are trying to stub, then the very next thing you do in either Mockito OR PowerMock is to specify what happens when that method is called - that is, to do the thenReturnpart. Each call to whenmust be followed by one and only one call to thenReturn, before you do any more calls to when. You made two calls to whenwithout calling thenReturn- that's your error.

但问题的真正原因是when在完成存根之前,您正在使用两个不同的对象。当您调用when,并提供您尝试存根的方法调用时,您在 Mockito 或 PowerMock 中所做的下一件事就是指定调用该方法时会发生什么 - 即完成该thenReturn部分。每次调用 to 之前when必须紧跟一个且仅一个调用 to thenReturn,然后再调用 to when。你在when没有打电话的情况下拨打了两次thenReturn- 那是你的错误。

回答by Ashish Kirpan

We can mock list properly for foreach loop. Please find below code snippet and explanation.

我们可以为 foreach 循环正确模拟列表。请在下面找到代码片段和解释。

This is my actual class method where I want to create test case by mocking list. this.nameListis a list object.

这是我的实际类方法,我想通过模拟列表创建测试用例。 this.nameList是一个列表对象。

public void setOptions(){
    // ....
    for (String str : this.nameList) {
        str = "-"+str;
    }
    // ....
}

The foreach loop internally works on iterator, so here we crated mock of iterator. Mockito framework has facility to return pair of values on particular method call by using Mockito.when().thenReturn(), i.e. on hasNext()we pass 1st true and on second call false, so that our loop will continue only two times. On next()we just return actual return value.

foreach 循环内部在迭代器上工作,所以在这里我们创建了迭代器的模拟。Mockito 框架可以通过 using 在特定方法调用时返回一对值Mockito.when().thenReturn(),即在hasNext()我们传递第一个 true 和第二个调用 false 时,这样我们的循环将只继续两次。在next()我们刚刚返回实际的返回值。

@Test
public void testSetOptions(){
    // ...
    Iterator<SampleFilter> itr = Mockito.mock(Iterator.class);
    Mockito.when(itr.hasNext()).thenReturn(true, false);
    Mockito.when(itr.next()).thenReturn(Mockito.any(String.class);  

    List mockNameList = Mockito.mock(List.class);
    Mockito.when(mockNameList.iterator()).thenReturn(itr);
    // ...
}

In this way we can avoid sending actual list to test by using mock of list.

通过这种方式,我们可以避免使用列表模拟发送实际列表进行测试。

回答by lyuboe

When dealing with mocking lists and iterating them, I always use something like:

在处理模拟列表并迭代它们时,我总是使用类似的东西:

@Spy
private List<Object> parts = new ArrayList<>();