运行测试时出现以下异常。我正在使用 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)
..........
来自 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;
}
}
原文由 Royal Rose 发布,翻译遵循 CC BY-SA 4.0 许可协议
您将模拟嵌套在模拟中。在完成对
MyMainModel
的模拟之前,您正在调用getSomeList()
,它会进行一些模拟。当你这样做时,Mockito 不喜欢它。代替
和
要了解这会导致问题的原因,您需要了解一点 Mockito 的工作原理,并了解 Java 中表达式和语句的计算顺序。
Mockito 无法读取您的源代码,因此为了弄清楚您要求它做什么,它在很大程度上依赖于静态状态。当您在模拟对象上调用方法时,Mockito 会将调用的详细信息记录在调用的内部列表中。
when
方法从列表中读取最后一个调用,并将此调用记录在它返回的OngoingStubbing
对象中。线
导致与 Mockito 的以下交互:
mainModel.getList()
被调用,when
被调用,thenReturn
在when
方法返回的OngoingStubbing
对象上被调用。The
thenReturn
method can then instruct the mock it received via theOngoingStubbing
method to handle any suitable call to thegetList
method to returnsomeModelList
.事实上,由于 Mockito 看不到你的代码,你也可以将你的 mocking 写成如下:
这种风格读起来有点不太清楚,特别是因为在这种情况下
null
必须被强制转换,但它会生成与 Mockito 相同的交互序列,并将获得与上述行相同的结果。然而,线
导致与 Mockito 的以下交互:
mainModel.getList()
被调用,when
被调用,mock
的SomeModel
(在getSomeList()
内),model.getName()
被调用,在这一点上,Mockito 感到困惑。它以为你在模拟
mainModel.getList()
,但现在你告诉它你想模拟model.getName()
方法。对于 Mockito,看起来您正在执行以下操作:这看起来很傻
Mockito
因为它不能确定你在做什么mainModel.getList()
。请注意,我们没有得到
thenReturn
方法调用,因为 JVM 在调用该方法之前需要评估该方法的参数。在这种情况下,这意味着调用getSomeList()
方法。通常,像 Mockito 那样依赖静态状态是一个糟糕的设计决策,因为它可能导致违反最小惊讶原则的情况。然而,Mockito 的设计确实使嘲弄变得清晰而富有表现力,即使它有时会导致惊讶。
最后,最新版本的 Mockito 在上面的错误消息中添加了额外的一行。这个额外的行表明您可能处于与此问题相同的情况: