在Mockito中检测到未完成的存根

Roy*_*ose 128 java mocking mockito

我在运行测试时遇到异常.我正在使用Mockito进行嘲弄.Mockito图书馆提到的提示没有帮助.

org.mockito.exceptions.misusing.UnfinishedStubbingException: 
Unfinished stubbing detected here:
    -> at com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)

    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!

        at a.b.DomainTestFactory.myTest(DomainTestFactory.java:276)
        ..........
Run Code Online (Sandbox Code Playgroud)

来自DomainTestFactory的测试代码.当我运行以下测试时,我看到了异常

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}

private List<SomeModel> getSomeList() {
    SomeModel model = Mockito.mock(SomeModel.class);
    Mockito.when(model.getName()).thenReturn("SomeName"); --> Line 276
    Mockito.when(model.getAddress()).thenReturn("Address");
    return Arrays.asList(model);
}

public class SomeModel extends SomeInputModel{
    protected String address;
    protected List<SomeClass> properties;

    public SomeModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    public String getAddress() {
        return this.address;
    }

}

public class SomeInputModel{

    public NetworkInputModel() {
        this.Properties = new java.util.ArrayList<SomeClass>(); 
    }

    protected String Name;
    protected List<SomeClass> properties;

    public String getName() {
        return this.Name;
    }

    public void setName(String value) {
        this.Name = value;
    }
}
Run Code Online (Sandbox Code Playgroud)

Luk*_*ard 319

你在嘲弄里面嘲弄你.getSomeList()在你完成模拟之前,你正在打电话,这会做一些嘲弄MyMainModel.当你这样做时,Mockito不喜欢它.

更换

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}
Run Code Online (Sandbox Code Playgroud)

@Test
public myTest(){
    MyMainModel mainModel =  Mockito.mock(MyMainModel.class);
    List<SomeModel> someModelList = getSomeList();
    Mockito.when(mainModel.getList()).thenReturn(someModelList);
}
Run Code Online (Sandbox Code Playgroud)

要理解为什么会导致问题,您需要了解Mockito的工作原理,并了解Java中的表达式和语句的排序顺序.

Mockito无法读取您的源代码,因此为了弄清楚您要求它做什么,它依赖于静态状态.当您在模拟对象上调用方法时,Mockito会在内部调用列表中记录调用的详细信息.该when方法从列表中读取最后一个这些调用,并将此调用记录在OngoingStubbing它返回的对象中.

这条线

Mockito.when(mainModel.getList()).thenReturn(someModelList);
Run Code Online (Sandbox Code Playgroud)

导致以下与Mockito的互动:

  • mainModel.getList()调用模拟方法,
  • when调用静态方法,
  • 对方法返回thenReturnOngoingStubbing对象调用when方法.

thenReturn然后,该方法可以指示通过该OngoingStubbing方法接收的模拟,以处理对该getList方法返回的任何合适的调用someModelList.

事实上,由于Mockito无法看到您的代码,您还可以按如下方式编写模拟:

mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);
Run Code Online (Sandbox Code Playgroud)

这种风格稍微不那么清晰,特别是因为在这种情况下null必须进行铸造,但它与Mockito产生相同的交互顺序,并将获得与上面一行相同的结果.

但是,行

Mockito.when(mainModel.getList()).thenReturn(getSomeList());
Run Code Online (Sandbox Code Playgroud)

导致以下与Mockito的互动:

  1. mainModel.getList()调用模拟方法,
  2. when调用静态方法,
  3. 创建一个新mockSomeModel(内部getSomeList()),
  4. model.getName()调用模拟方法,

此时Mockito感到困惑.它以为你在嘲笑mainModel.getList(),但现在你告诉它你要嘲笑这个model.getName()方法.对Mockito来说,看起来你正在做以下事情:

when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);
Run Code Online (Sandbox Code Playgroud)

这看起来很傻,Mockito因为它不能确定你在做什么mainModel.getList().

请注意,我们没有进入thenReturn方法调用,因为JVM需要在调用方法之前评估此方法的参数.在这种情况下,这意味着调用该getSomeList()方法.

一般来说,依靠静态来做出糟糕的设计决定,正如Mockito所做的那样,因为它可能会导致违反最小惊讶原则的情况.然而,Mockito的设计确实可以做出清晰而富有表现力的嘲弄,即使它有时会让人感到惊讶.

最后,最近版本的Mockito在上面的错误消息中添加了一个额外的行.这个额外的行表示您可能与此问题处于相同的情况:

3:如果完成,你在"thenReturn"指令之前将另一个模拟内部的行为存根

  • 很好的答案,喜欢!我自己要花很长时间才能找到这个 (5认同)
  • 很好的回答卢克!用简单的话非常详细的解释。谢谢。 (2认同)

Pun*_*ari 7

AbcService abcService = mock(AbcService.class);

检查语法:

  1. doThrow(new RunTimeException()).when(abcService).add(any(), any())

常见错误如下所示:

A。doThrow(new RunTimeException()).when(abcService.add(any(), any()))

同样,检查when().thenReturn(),等等。