Mockito высмеивает новый вызов экземпляра с параметрами - PullRequest
0 голосов
/ 07 декабря 2018

В школьных целях я создаю приложение, которое работает с фондовым 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, чтобы попробовать идостичь этого.

Ответы [ 3 ]

0 голосов
/ 07 декабря 2018

Объект 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();

// ...

0 голосов
/ 07 декабря 2018

Код в главном классе создает новый экземпляр 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, а при проверке он должен возвращать ссылку 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 при имитации.

0 голосов
/ 07 декабря 2018

Вы можете использовать метод thenThrow () .Ниже приведен пример

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