[英]The deep mock is not working as member of @InjectMocks
注釋@InjectMocks
為我們提供了對存根/填充私有成員@InjectMocks
的方法。 這是當我們對假成員進行偽造時發生問題的概念代碼。
public class TestBuilder{
@Spy
private StubComponent componentA = new StubComponent();
@Mock
private FakeComponent componentB;
@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);
public static Class TestTarget{
private StubComponent componentA;
private FakeComponent componentB;
public ShimmedResultB testInvokation(String para){
componentA.doCallRealMethod();
ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
return shouldNotBeNull;
}
}
private TestBuilder(){
MockitoAnnotations.initMocks(this);
//Shim the real component A with partial stubbed
doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());
//Shim the fake component B
//************The issue is here****************
componentB = mock(FakeComponent.class);
//*********************************************
when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);
}
public TestTarget getTargetInstance(){
return this.targetInstance;
}
public static TestTarget build(){
return (new TestBuilder()).getTargetInstance();
}
public static main(String[] args){
TestTarget testInstance = TestBuilder.build();
ShimmedResultB result = testInstance.testInvokation("");
assertThat(result, not(equalTo(null)));
}
}
問題是當我們模擬Fake componentB
。 然后someShimmedMethod
將返回null。 看來InjectMocks
無法將mock()
攜帶給私有成員。
以下是一些術語定義:
StubComponent:測試將作為私有成員滲透到此組件。 但是,有些方法可能無法通過。 我們可以使用其公開方法。 該組件可能具有較小的依賴性范圍,這些依賴性范圍很容易由本地資源啟動。
FakeComponent:該組件將在其他地方進行測試。 在這里,我們只能構建模擬實例,並填充測試目標將利用的所有方法。
存根:@Spy可以幫助我們鈎住存根成員。 私人成員不是100%真實的。 但是某些殘存的部分可能會讓測試滲透到該私有成員中。
Shim:@Mock將為我們提供一個空指針,直到initMocks。 因此,我們可以開始設計initMocks之后的Fake組件的返回。 這是@InjectMocks的魔力。 但是,這是最棘手的部分,因為開發人員希望直觀地初始化componentB的所有內容並嘲笑(FakeComponent.class)。 這將清除所有填充的設計,並使您的聲明失敗。
================================================== ================
感謝Maciej的答復,對我翻譯測試用例的結構時出現的錯字表示抱歉。 並且讓我對Maciej的答案進行更清晰的描述來提出這個問題。
public class TestBuilder{
@Spy
private StubComponent componentA = new StubComponent();
@Mock
private FakeComponent componentB;
@InjectMocks
private TestTarget targetInstance = mock(TestTarget.class);
public static Class TestTarget{
private StubComponent componentA;
private FakeComponent componentB;
public ShimmedResultB testInvokation(String para){
componentA.doCallRealMethod();
ShimmedResultA shimmedResultA = componentA.someUnableToStubbedMethod(para);
ShimmedResultB shouldNotBeNull = componentB.someShimmedMethod(shimmedResultA);
return shouldNotBeNull;
}
public TestTarget(){
//The FakeComponent has some specific remote resource
//And could not be initialized here
componentB = new FakeComponent();
//We will use mock server to test this FakeComponent else where
}
}
private TestBuilder(){
//Hook the testing Function for trigger the step in
doCallRealMethod().when(this.targetInstance).testInvokation(anyString());
//Inject Stubbed and Faked Private Member for testing
MockitoAnnotations.initMocks(this);
//Shim the real component A with partial stubbed
doReturn(shimmedResultA).when(componentA).someUnableToStubbedMethod(any());
//************The issue is here****************
componentB = mock(FakeComponent.class);
//*********************************************
//Shim the leveraged method of fake componentB
when(componentB.someShimmedMethod(any())).thenReturn(shimmedResultB);
}
public TestTarget getTargetInstance(){
return this.targetInstance;
}
public static TestTarget build(){
return (new TestBuilder()).getTargetInstance();
}
public static main(String[] args){
TestTarget testInstance = TestBuilder.build();
//The doRealCall hook will trigger the testing
ShimmedResultB result = testInstance.testInvokation("");
assertThat(result, not(equalTo(null)));
}
}
第二個概念代碼中添加了一些內容:
componentB是我們不希望介入的范圍。但是,TestTarget在其構造函數中使用componentB進行初始化。 當我們有一個與遠程源相關的工具時,這很常見。 我們使用模擬服務器或其他技術來獨立測試componentB。 因此,我們只能使用模擬(TestTarget.class)。
由於我們嘲笑了TestTarget。 我錯過了一件事,我們需要使用doCallRealMethod()。when(targetInstance)來觸發testInvokation()。 這限制了targetInstance的空聲明。 我們需要模擬()並掛鈎doCallRealMethod。
因此,結果是我們需要將@Mock保留為空,而沒有任何模擬()以便讓@InjectMocks處理墊片。 當我們使用@InjectMocks時,我們發現這很棘手。
問題在於@InjectMocks定義:
@InjectMocks
private class TestTarget targetInstance = mock(TestTarget.class);
被測類絕不能是模擬類(也是為什么要使用class關鍵字)。
嘗試使用:
@InjectMocks
private TestTarget targetInstance = new TestTarget();
或者簡單地:
@InjectMocks
private TestTarget targetInstance;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.