【问题标题】:Create a mocked list by mockito通过 mockito 创建一个模拟列表
【发布时间】:2013-09-02 01:39:36
【问题描述】:

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

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

这是我的实现:

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;
}

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

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

详情:

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!

我该如何解决?谢谢

【问题讨论】:

标签: java unit-testing junit mocking mockito


【解决方案1】:

好吧,这是一件坏事。不要模拟列表;相反,模拟列表中的各个对象。请参阅Mockito: mocking an arraylist that will be looped in a for loop 了解如何执行此操作。

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

但问题的真正原因是您在完成存根之前在两个不同的对象上使用了when。当您调用 when 并提供您尝试存根的方法调用时,您在 Mockito 或 PowerMock 中所做的下一件事就是指定调用该方法时会发生什么 - 即执行 @987654324 @ 部分。每次对when 的调用必须跟一个且只有一个对thenReturn 的调用,然后再对when 进行任何调用。您两次调用when 却没有调用thenReturn - 那是您的错误。

【讨论】:

  • 但如果你真的需要,你会如何模拟一个列表?
  • 你为什么要这么做?总是做错事。这就像在问“如果你真的必须用锤子来驱动螺丝怎么办”。这是错误的方法 - 工作的错误工具。
  • 你如何返回一个普通的列表然后里面有模拟项目?
  • 问题:我如何解决X?答:不要做X,而是做Y。我不明白为什么这是公认的答案。
  • @GabrielOshiro - 我会尽力帮助您理解。 OP 发布了一些包含错误的代码,并询问了“我该如何修复它”的问题。我的第三段解释了他们的错误。我的回答为他们的问题提供了解决方案。所以我实际上已经完全回答了他们的问题。我希望这可以帮助您“了解为什么”这是公认的答案。
【解决方案2】:

在处理模拟列表并对其进行迭代时,我总是使用类似的东西:

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

【讨论】:

    【解决方案3】:

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

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

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

    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);
        // ...
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-16
      • 2013-11-17
      • 1970-01-01
      • 2023-02-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多