簡體   English   中英

Mockito模擬帶有參數的新實例調用

[英]Mockito mocking a new instance call with parameters

出於學校目的,我正在創建一個使用股票API的應用程序。

我正在嘗試編寫一種測試方法,以獲取過去10年的所有庫存數據。 我不想拋出所有的數據,而是想拋出一個異常。

我要測試的方法:

@Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
    List<StockData> stockData;

    AlphaVantageConnector apiConnector = new AlphaVantageConnector(APIKEY, TIMEOUT);
    TimeSeries stockTimeSeries = new TimeSeries(apiConnector);

    try {

        Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
        stockData = responseDaily.getStockData();

    } catch (AlphaVantageException e) {

        LOGGER.log(Level.SEVERE, "something went wrong: ", e);

        throw e;

    }

    return stockData;
}

stockTimeSeries.daily(....)調用可能引發AlphaVantageException。

我像這樣嘲笑TimeSeries類:

TimeSeries stockTimeSeries = mock(TimeSeries.class);

在測試類中,我想模擬此調用,並返回一個異常而不是實際數據。

when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));

無論我如何嘗試模擬這段代碼,它都不會拋出異常。 它總是會執行代碼,並返回有效的庫存數據,而不是像我嘗試的那樣拋出異常。

我該如何模擬這段代碼,以便拋出測試中期望的異常。

AlphaVantageConnector,TimeSeries和Daily類是用於訪問常規API的庫的一部分,因此我無法更改這些類。

我正在使用JUnit 4.12和Mockito嘗試實現這一目標。

您可以使用thenThrow()方法。 以下是示例

 @Test(expected = NullPointerException.class) public void whenConfigNonVoidRetunMethodToThrowEx_thenExIsThrown() { MyDictionary dictMock = mock(MyDictionary.class); when(dictMock.getMeaning(anyString())) .thenThrow(NullPointerException.class); dictMock.getMeaning("word"); 

TimeSeries對象是在方法本身中創建的,因此您無法對其進行模擬-模擬旨在模擬成員。

你可以做的是做類似的事情

class YourClass {
   private Supplier<TimeSeries> seriesCreator = () -> {
       return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
   }

用於在您的方法中創建系列

@Override
public List<StockData> getAllTeslaStockData() throws AlphaVantageException {
    TimeSeries stockTimeSeries = seriesCreator.get();

現在您可以嘲笑那個Supplier

@Mock Supplier<TimeSeries> seriesCreatorMock;
@InjectMocks MyClass sut;

在你的測試中

@Test(expected = AlphaVantageException.class)
void testException() {
    when(seriesCreatorMock.get()).thenThrow(new AlphaVantageException());
    sut.getAllTeslaStockData()
}

編輯:正如吳哥在評論中建議的那樣,干凈的方法是

class SeriesCreator implements Supplier<TimeSeries> {
    public TimeSeries get() {
       return new TimeSeries(new AlphaVantageConnector(APIKEY, TIMEOUT));
    }
}

class YourClass {
   private Supplier<TimeSeries> seriesCreator = new SeriesCreator();

// ...

主類中的代碼正在創建一個TimeSeries新實例,實例將在每次調用此方法時使用,因此完全不會使用模擬的TimeSeries對象。

TimeSeries stockTimeSeries = new TimeSeries(apiConnector);  // --> This is not getting mocked

    try {

        Daily responseDaily = stockTimeSeries.daily("TSLA", OutputSize.FULL);
        stockData = responseDaily.getStockData();

    }

您應該在您的類中創建另一個方法(如果更好地滿足SOLID原則,甚至可以創建一個單獨的類),該方法將返回TimeSeries對象。 就像是:-

<access modifier> TimeSeries getTimeSeries(...) {

}

然后應該在Junit中對這個方法進行TimeSeries stockTimeSeries = mock(TimeSeries.class); ,並且在TimeSeries stockTimeSeries = mock(TimeSeries.class);時,它應該返回Mocked TimeSeries引用(在TimeSeries stockTimeSeries = mock(TimeSeries.class); )。 您將需要在主類上使用.spy() (除非您使用其他類來創建TimeSeries對象),以便能夠模擬特定的方法getTimeSeries()而不是其他方法。

MainClass mainObject = Mockito.spy(new MainClass());
Mockito.when(mainObject.getTimeSeries()).thenReturn(stockTimeSeries);

然后,調用stockTimeSeries.daily()的方法將實際上被您現有的代碼嘲笑:

when(stockTimeSeries.daily("TSLA", OutputSize.FULL)).thenThrow(new AlphaVantageException("No stock data available"));

注意:在.anyString()您還應該考慮使用Mockito API提供的.anyString .anyString()樣式方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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