Модульные тесты для ConnectException и IOException

#java #junit

#java #junit

Вопрос:

У меня есть модульный тест, который проверяет, выдает ли метод ошибку или нет.

 @Test
public void getStockPriceWithNetworkErrorThrowsException()
{
    StockPriceFetcher stockPriceFetcherWithNetworkError = Mockito.mock(StockPriceFetcher.class);
    when(stockPriceFetcherWithNetworkError.getPrice("YHOO"))
            .thenThrow(new ConnectException("Network error"));

    assetValue = new AssetValue(stockPriceFetcherWithNetworkError);

    try
    {
        assetValue.getStockPrice("YHOO");
        fail("Expected exception for network error.");
    }
    catch(ConnectException e){
        assertEquals(e.getMessage(), "Network error");
    }
}
  

getPrice это метод из интерфейса stockPriceFetcher и getStockPrice просто возвращает то, что getPrice() возвращает. Я хочу, чтобы a ConnectException был выдан, но у меня есть ошибка в блоке catch, потому ConnectException что он никогда не выдается в блоке try.

Могу ли я в любом случае заставить этот блок try бросить a ConnectException ?

Комментарии:

1. Как getStockPrice метод-оболочка обрабатывает исключение, вызванное getPrice ? Вызывает ли это исключение дальше?

2. Не уверен, что именно вы имеете в виду, но getStockPrice вызывается в более позднем методе, и этот метод улавливает ConnectException, который getStockPrice получает от getPrice

3. Тогда это ваш ответ. Я опубликую ниже

4. Вы не должны писать модульные тесты, которые проверяют текст исключений. ConnectException предоставляется JDK и не содержит текста "Network error" , и, даже если бы он был, он мог измениться в любом выпуске или при любом изменении локали. Все, что вам следует проверить здесь, это то, было ли выдано исключение.

Ответ №1:

Самый простой способ решить эту проблему — заменить следующую строку:

когда (stockPriceFetcherWithNetworkError.getPrice(«YHOO»))

с помощью линии:

когда(stockPriceFetcherWithNetworkError.getStockPrice(«YHOO»))

Но убедитесь, что getStockPrice() включает в себя блок try {} catch(ConnectException e){} .

Кажется, что вы не вызываете ConnectException в методе getStockPrice().

 getStockPrice(String str) {

    getPrice(str) {
     //  Here the ConnectException is thrown
     }
   // here should appear another catch that throws the error to the upper level
}
  

Без блока try{} catch{} в методе getStockPrice() исключение не может быть перехвачено в любом месте, где вызывается метод.
Вот почему вы также должны реализовать макет getStockPrice() .

Когда вы добавите блок try{} catch(ConnectException e) {}, он будет отлично работать.

Ответ №2:

Дополните свою @Test аннотацию ее expected параметром.

 @Test(expected=ConnectException.class)
public void testConnectExceptionThrown() {
    // your test here
}
  

Тест будет пройден только в том случае, если при выполнении метода тестирования генерируется ожидаемое исключение. Если тест завершается без неперехваченного ConnectException, он будет рассматриваться как сбой. Обычно так вы проверяете исключения.

Конечно, если вы хотите протестировать сообщение об исключении, то это его не сократит. Вам нужно будет в основном делать это так, как вы уже написали. Тем не менее, я бы переместил утверждение из блока catch.

 @Test
public void getStockPriceWithNetworkErrorThrowsException()
{
    StockPriceFetcher stockPriceFetcherWithNetworkError = Mockito.mock(StockPriceFetcher.class);
    when(stockPriceFetcherWithNetworkError.getPrice("YHOO"))
            .thenThrow(new ConnectException("Network error"));

    assetValue = new AssetValue(stockPriceFetcherWithNetworkError);

    String exceptionMsg = null;
    try
    {
        assetValue.getStockPrice("YHOO");
        fail("Expected exception for network error.");
    }
    catch(ConnectException e){
        exceptionMsg = e.getMessage();
    }

    assertEquals("Should have thrown ConnectException with correct message",
        "Network error", exceptionMsg);
}
  

Ответ №3:

В свете того, что обсуждалось в комментариях, я почти уверен, что ваша проблема заключается в том, что getStockPrice не генерирует исключение, которое оно получает от getPrice дальнейшего, поэтому, по сути, оно не доходит до того, что оно передается вызывающему экземпляру getStockPrice (например, вашему тестовому классу).

Что вы можете сделать, так это:

  • измените свой тест, чтобы точно ожидать, что происходит в catch блоке, getStockPrice если это поведение, которое вы хотите, чтобы ваша система имела ИЛИ

  • измените свой getStockPrice метод, чтобы генерировать исключение, которое он получает, getPrice вместо его перехвата, т.Е. Добавьте throws к нему объявление и удалите try...catch блоки. Тогда ваш тест будет вести себя так, как ожидалось, так, как он написан прямо сейчас