簡體   English   中英

Mockito何時/然后不返回期望值

[英]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。調用的方法。 通常,您只模擬外部依賴項。

實際上,有兩種創建測試對象的方法: mockspy 入門者將根據您提供的類創建一個新對象,該類的內部狀態為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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM