問題描述
我在運行測試時遇到以下異常.我正在使用 Mockito 進行模擬.Mockito 庫提到的提示沒有幫助.
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)
..........
來自 DomainTestFactory
的測試代碼.當(dāng)我運行以下測試時,我看到了異常.
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;
}
}
推薦答案
你在 mocking 中嵌套了 mocking.在完成對 MyMainModel
的模擬之前,您正在調(diào)用 getSomeList()
,它會進行一些模擬.當(dāng)你這樣做時,Mockito 不喜歡它.
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.
替換
@Test
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
Mockito.when(mainModel.getList()).thenReturn(getSomeList()); --> Line 355
}
與
@Test
public myTest(){
MyMainModel mainModel = Mockito.mock(MyMainModel.class);
List<SomeModel> someModelList = getSomeList();
Mockito.when(mainModel.getList()).thenReturn(someModelList);
}
要了解這會導(dǎo)致問題的原因,您需要了解一點 Mockito 的工作原理,并了解 Java 中表達式和語句的計算順序.
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 無法讀取您的源代碼,因此為了弄清楚您要求它做什么,它在很大程度上依賴于靜態(tài)狀態(tài).當(dāng)您在模擬對象上調(diào)用方法時,Mockito 會將調(diào)用的詳細信息記錄在調(diào)用的內(nèi)部列表中.when
方法從列表中讀取這些調(diào)用中的最后一個,并將此調(diào)用記錄在它返回的 OngoingStubbing
對象中.
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.
線
Mockito.when(mainModel.getList()).thenReturn(someModelList);
導(dǎo)致與 Mockito 的以下交互:
causes the following interactions with Mockito:
- Mock 方法
mainModel.getList()
被調(diào)用, - 靜態(tài)方法
當(dāng)
被調(diào)用時, - 方法
thenReturn
在when
方法返回的OngoingStubbing
對象上調(diào)用.
- Mock method
mainModel.getList()
is called, - Static method
when
is called, - Method
thenReturn
is called on theOngoingStubbing
object returned by thewhen
method.
thenReturn
方法然后可以指示它通過 OngoingStubbing
方法接收到的模擬來處理對 getList
方法的任何合適的調(diào)用以返回 <代碼>someModelList.
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
.
其實由于Mockito看不到你的代碼,你也可以這樣寫你的mocking:
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);
這種風(fēng)格讀起來有點不太清楚,特別是因為在這種情況下 null
必須被強制轉(zhuǎn)換,但它會生成與 Mockito 相同的交互序列,并將獲得與該行相同的結(jié)果以上.
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.
但是,行
Mockito.when(mainModel.getList()).thenReturn(getSomeList());
導(dǎo)致與 Mockito 的以下交互:
causes the following interactions with Mockito:
- Mock 方法
mainModel.getList()
被調(diào)用, - 靜態(tài)方法
當(dāng)
被調(diào)用時, SomeModel
的新mock
已創(chuàng)建(在getSomeList()
內(nèi)),- 調(diào)用模擬方法
model.getName()
,
- Mock method
mainModel.getList()
is called, - Static method
when
is called, - A new
mock
ofSomeModel
is created (insidegetSomeList()
), - Mock method
model.getName()
is called,
此時 Mockito 感到困惑.它以為你在模擬 mainModel.getList()
,但現(xiàn)在你告訴它你想模擬 model.getName()
方法.對于 Mockito,您似乎正在執(zhí)行以下操作:
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(...);
這對于 Mockito
來說看起來很傻,因為它無法確定您在用 mainModel.getList()
做什么.
This looks silly to Mockito
as it can't be sure what you're doing with mainModel.getList()
.
請注意,我們沒有到達 thenReturn
方法調(diào)用,因為 JVM 需要先評估該方法的參數(shù),然后才能調(diào)用該方法.在這種情況下,這意味著調(diào)用 getSomeList()
方法.
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.
通常,像 Mockito 那樣依賴靜態(tài)狀態(tài)是一個糟糕的設(shè)計決策,因為它可能導(dǎo)致違反最小驚訝原則的情況.然而,Mockito 的設(shè)計確實可以進行清晰而富有表現(xiàn)力的嘲弄,即使有時會讓人感到驚訝.
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.
最后,最新版本的 Mockito 在上面的錯誤消息中添加了額外的一行.這個額外的行表明您可能與此問題處于相同的情況:
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:如果完成,您將在thenReturn"指令之前對內(nèi)部另一個模擬的行為進行存根
3: you are stubbing the behaviour of another mock inside before 'thenReturn' instruction if completed
這篇關(guān)于在 Mockito 中檢測到未完成的存根的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網(wǎng)!