在Mockito中检测到未完成的短截线 [英] Unfinished Stubbing Detected in Mockito

查看:1203
本文介绍了在Mockito中检测到未完成的短截线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

  org.mockito.exceptions.misusing.UnfinishedStubbingException:
未完成的存根在这里检测到:
- >在com.a.b.DomainTestFactory.myTest(DomainTestFactory.java:355)

例如thenReturn()可能会丢失。
正确存根的例子:
when(mock.isOk())。thenReturn(true);
when(mock.isOk())。thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
提示:
1.缺少thenReturn()
2.你试图找到最终方法,你顽皮的开发人员!

at abDomainTestFactory.myTest(DomainTestFactory.java:276)
..........

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

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

私人列表< SomeModel> getSomeList(){
SomeModel model = Mockito.mock(SomeModel.class);
Mockito.when(model.getName())。thenReturn(SomeName); - >第276行
Mockito.when(model.getAddress())。thenReturn(Address);
返回Arrays.asList(model);
}

公共类SomeModel扩展SomeInputModel {
protected String address;
protected List< SomeClass>性能;

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

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

}

公共类SomeInputModel {

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

protected String Name;
protected List< SomeClass>性能;

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

public void setName(String value){
this.Name = value;
}
}


解决方案

你在模仿中嵌套嘲弄。在完成 MyMainModel 的模拟之前,你正在调用 getSomeList(),这会做一些模拟。当你这样做时,Mockito不喜欢它。



替换

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

  @Test 
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
列表< SomeModel> someModelList = getSomeList();
Mockito.when(mainModel.getList())。thenReturn(someModelList);
}

要了解导致问题的原因,您需要了解一些如何Mockito工作,也知道用Java评估表达式和语句的顺序。



Mockito无法读取你的源代码,所以为了弄明白你是什么它要求它做,它依赖于静态。当您在模拟对象上调用方法时,Mockito会在内部调用列表中记录调用的详细信息。当方法从列表中读取最后一个这样的调用时,将这个调用记录在它返回的 OngoingStubbing 对象中。 / p>

该行

  Mockito.when(mainModel.getList()) .thenReturn(someModelList); 

导致以下与Mockito的互动:




  • 模拟方法 mainModel.getList()被调用,

  • 静态方法调用时,

  • OngoingStubbing上调用 thenReturn
  • code> 方法时返回的对象。


thenReturn 方法然后可以通过 OngoingStubbing 方法指示它收到的模拟来处理对 getList 返回 someModelList 的方法。



事实上,由于Mockito不能看到你的代码,你也可以按如下方式编写你的模拟:

  mainModel.getList(); 
Mockito.when((List< SomeModel>)null).thenReturn(someModelList);

这种风格不太清楚,特别是因为在这种情况下 null 必须进行转换,但它会与Mockito生成相同的交互序列,并且会获得与上面一行相同的结果。



但是,行

  Mockito.when(mainModel.getList())。thenReturn(getSomeList()); 

导致以下与Mockito的互动:


  1. 模拟方法 mainModel.getList()被调用,

  2. 静态方法被调用时,

  3. 一个新的模拟 SomeModel 已创建(在 getSomeList()内),

  4. 模拟方法 model.getName()被调用,

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

  when(mainModel.getList()); 
// ... ...
when(model.getName())。thenReturn(...);

对于 Mockito 这看起来很傻不知道你在做什么 mainModel.getList()



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



一般来说,依赖它是一个糟糕的设计决策在静态上,正如Mockito所做的那样,因为它可能导致违反最小惊讶原则的情况。然而,Mockito的设计确实会产生清晰而富有表现力的嘲讽,即使它有时会让人感到惊讶。



最后,最近版本的Mockito在上面的错误信息中添加了一条额外的行。这个额外的行表明你可能与这个问题处于相同的情况:


3:你在之前中存在另一个模拟行为的行为然后返回'指令完成



I am getting following exception while running the tests. I am using Mockito for mocking. The hints mentioned by Mockito library are not helping.

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)
        ..........

Test Code from DomainTestFactory. When I run the following test, I see the exception

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

解决方案

You're nesting mocking inside of mocking. You're calling getSomeList(), which does some mocking, before you've finished the mocking for MyMainModel. Mockito doesn't like it when you do this.

Replace

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

with

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

To understand why this causes a problem, you need to know a little about how Mockito works, and also be aware in what order expressions and statements are evaluated in Java.

Mockito can't read your source code, so in order to figure out what you are asking it to do, it relies a lot on static state. When you call a method on a mock object, Mockito records the details of the call in an internal list of invocations. The when method reads the last of these invocations off the list and records this invocation in the OngoingStubbing object it returns.

The line

Mockito.when(mainModel.getList()).thenReturn(someModelList);

causes the following interactions with Mockito:

  • Mock method mainModel.getList() is called,
  • Static method when is called,
  • Method thenReturn is called on the OngoingStubbing object returned by the when method.

The thenReturn method can then instruct the mock it received via the OngoingStubbing method to handle any suitable call to the getList method to return someModelList.

In fact, as Mockito can't see your code, you can also write your mocking as follows:

mainModel.getList();
Mockito.when((List<SomeModel>)null).thenReturn(someModelList);

This style is somewhat less clear to read, especially since in this case the null has to be casted, but it generates the same sequence of interactions with Mockito and will achieve the same result as the line above.

However, the line

Mockito.when(mainModel.getList()).thenReturn(getSomeList());

causes the following interactions with Mockito:

  1. Mock method mainModel.getList() is called,
  2. Static method when is called,
  3. A new mock of SomeModel is created (inside getSomeList()),
  4. Mock method model.getName() is called,

At this point Mockito gets confused. It thought you were mocking mainModel.getList(), but now you're telling it you want to mock the model.getName() method. To Mockito, it looks like you're doing the following:

when(mainModel.getList());
// ...
when(model.getName()).thenReturn(...);

This looks silly to Mockito as it can't be sure what you're doing with mainModel.getList().

Note that we did not get to the thenReturn method call, as the JVM needs to evaluate the parameters to this method before it can call the method. In this case, this means calling the getSomeList() method.

Generally it is a bad design decision to rely on static state, as Mockito does, because it can lead to cases where the Principle of Least Astonishment is violated. However, Mockito's design does make for clear and expressive mocking, even if it leads to astonishment sometimes.

Finally, recent versions of Mockito add an extra line to the error message above. This extra line indicates you may be in the same situation as this question:

3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed

这篇关于在Mockito中检测到未完成的短截线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆