通过mockito创建一个模拟列表

Tie*_*yen 28 java junit unit-testing mocking mockito

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

 for (String history : list) {
        //code here
    }
Run Code Online (Sandbox Code Playgroud)

这是我的实现:

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;
}
Run Code Online (Sandbox Code Playgroud)

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

OngoingStubbing<DyActionHistory> osHistory = when(iterHistory.next());
Run Code Online (Sandbox Code Playgroud)

详情:

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!
Run Code Online (Sandbox Code Playgroud)

我该如何解决?谢谢

Daw*_*ica 32

好的,这是一件坏事.不要嘲笑一个清单; 相反,模拟列表中的各个对象.请参阅Mockito:嘲笑一个arraylist,它将在for循环中循环以获取如何执行此操作.

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

但问题的真正原因是when,在完成存根之前,您正在使用两个不同的对象.当你调用when并提供你试图存根的方法调用时,你在Mockito或PowerMock中做的下一件事就是指定在调用该方法时会发生什么 - 也就是做thenReturn部件.在您再次拨打电话之前,每次通话when必须跟随一次且仅一次通话.你没有打电话就打了两次电话- 这是你的错误.thenReturnwhenwhenthenReturn

  • 你真的为什么要这么做?这总是错误的做法.这就像问"如果你真的不得不用锤子来驱动螺丝".这是错误的方法 - 错误的工作工具. (3认同)
  • 问题:如何求解X?答:不要做X,请做Y。我不明白为什么这是公认的答案。 (2认同)
  • @GabrielOshiro - 我会尽力帮助你理解。OP 发布了一些带有错误的代码,并询问了“我该如何修复它”的问题。我的第三段解释了他们的错误。我的回答为他们的问题提供了解决方案。所以我实际上已经完整地回答了他们的问题。我希望这可以帮助您“了解为什么”这是公认的答案。 (2认同)

小智 10

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

@Spy
private List<Object> parts = new ArrayList<>();
Run Code Online (Sandbox Code Playgroud)


小智 5

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

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

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

foreach循环在内部在迭代器上起作用,因此在这里我们创建了迭代器的模拟。Mockito框架具有使用来在特定方法调用上返回一对值的功能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);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

这样,我们可以避免使用列表模拟发送实际的列表进行测试。