[英]Mockito when/then not returning expected value
我正在嘗試使用“ any”匹配器對這個getKeyFromStream方法進行存根。 我嘗試了更明確和不太明確的(anyObject()),但是無論我如何嘗試,此存根都不會在我的單元測試中返回fooKey。
我想知道是否是因為它受到保護,或者我缺少其他東西或做錯了什么。 在整個測試中,我還有其他when / then語句在起作用,但是由於某種原因,事實並非如此。
注意:getKeyFromStream通常使用byteArrayInputStream,但是我嘗試將其與InputStream匹配,但都嘗試了無濟於事。
public class FooKeyRetriever() //Mocked this guy
{
public FooKey getKey(String keyName) throws KeyException {
return getKeyFromStream(getKeyStream(keyName, false), keyName);
}
//Stubbed this method to return a key object which has been mocked
protected FooKey getKeyFromStream(InputStream keyStream, String keyName){
//Some code
return fooKey;
}
}
單元測試
@Mock
private FooKeyRetriever mockKeyRetriever;
@Mock
private FooKey fooKey;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testGetFooKey() throws Exception {
when(foo.getKeyFromStream(any(InputStream.class),any(String.class))).thenReturn(fooKey);
FooKey fooKey = mockKeyRetriever.getKey("irrelevant_key");
assertNotNull(fooKey);
}
單元測試的問題在於,您正在嘗試模擬要測試的實際類的方法,但實際上無法調用模擬方法,因為除非您在該方法上聲明了模擬的返回值,否則它將返回null。調用的方法。 通常,您只模擬外部依賴項。
實際上,有兩種創建測試對象的方法: mock
和spy
。 入門者將根據您提供的類創建一個新對象,該類的內部狀態為null,並且在每個調用的方法上都返回null
。 這就是為什么您需要為方法調用定義某些返回值的原因。 另一方面,如果為某些方法定義了“模擬定義”,則spy
會創建一個真實的對象並攔截方法調用。
Mockito和PowerMock提供了兩種定義模擬方法的方法:
// method 1
when(mockedObject.methodToMock(any(Param1.class), any(Param2.class),...)
.thenReturn(answer);
when(mockedObject, method(Dependency.class, "methodToMock", Parameter1.class, Parameter2.class, ...)
.thenReturn(answer);
要么
// method 2
doReturn(answer).when(mockedObject).methodToMock(param1, param2);
所不同的是, method 1
將執行方法實現,而后一種則不會。 如果您要處理spy
對象,這很重要,因為您有時不想執行所調用方法中的真實代碼,而只是替換代碼或返回預定義的值!
雖然和的Mockito提供PowerMock一個doCallRealMethod()
您可以定義的,而不是doReturn(...)
或doThrow(...)
這將調用和您的真實對象中執行代碼和忽略任何模擬的方法return語句。 但是,在您要模擬被測類的方法的情況下,這並不是很有用。
可以通過以下方法“覆蓋”方法實現:
doAnswer(Answer<T>() {
@Override
public T answer(InvocationOnMock invocation) throws Throwable {
...
}
)
您可以在其中簡單地聲明所調用方法的邏輯。 因此,您可以利用此方法返回受保護方法的模擬結果:
import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import java.io.InputStream;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
public class FooKeyRetrieverTest {
@Test
public void testGetFooKey() throws Exception {
// Arrange
final FooKeyRetriever sut = spy(new FooKeyRetriever());
FooKey mockedKey = mock(FooKey.class);
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());
doAnswer(new Answer<FooKey>() {
public FooKey answer(InvocationOnMock invocation) throws Throwable {
return sut.getKeyFromStream(null, "");
}
}).when(sut).getKey(anyString());
// Act
FooKey ret = sut.getKey("test");
// Assert
assertThat(ret, sameInstance(mockedKey));
}
}
上面的代碼有效,但是請注意,它的語義與簡單地聲明getKey(...)
的返回值相同getKey(...)
doReturn(mockedKey).when(sut).getKey(anyString());
嘗試僅使用getKeyFromStream(...)
方式修改getKeyFromStream(...)
:
doReturn(mockedKey)
.when(sut).getKeyFromStream(any(InputStream.class), anyString());
如果不修改測試中的系統(SUT)的getKey(...)
,將不會實現任何目標,因為將執行getKey(...)
的真實代碼。 但是,如果模擬sut對象,則無法在// Act
部分中調用該方法,因為這將返回null。 如果你試試
doCallRealMethod().when(sut).getKey(anyString());
在模擬對象上,將調用真實方法,並且如前所述,這還將調用getKeyFromStream(...)
和getKeyStream(...)
的實際實現,而不管您指定為模擬方法是什么。
正如您可能自己看到的那樣,測試中的實際類的模擬方法不是那么有用,並且給您帶來的負擔超過了它提供的任何好處。 因此,如果您想要或需要完全測試私有/受保護的方法,或者僅堅持測試公共API(我建議這樣做),則取決於您或您企業的政策。 盡管重構的主要目的應該是改善代碼的總體設計,但是您也可以重構代碼以提高可測試性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.