繁体   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