[英]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.