Mockito "thenThrow" не генерирует исключение, когда ожидалось

У меня проблема при попытке протестировать класс, представляющий Rest Client. Я использую RestTemplate в Spring Boot.

Это абстрактный класс RestClient:

    public abstract class RestClient {
    ...

    public RestResponse sendPostRequest(URI baseUri, String resource, IRestRequest restRequest, ClassresponseClass)
            throws ServerException, ClientException {

        ...

        try {

            RestTemplate restTemplate = new RestTemplate();
            response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
            result = response.getBody();

            getLogger().debug("[{}] received", result);
            return result;
        } catch (HttpClientErrorException e) {
            throw new ClientException(e.getCause());
        } catch (HttpServerErrorException e) {
            throw new ServerException(e.getCause());
        } catch (Exception e) {
            getLogger().error("Error with cause: {}.", e.getMessage());
        }

        ...
    }
}

Это фактическая реализация:

    public class ActualRestClient extends RestClient {

    public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
        return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
    }
 }

Это тест:

@RunWith(PowerMockRunner.class)
@PrepareForTest({ActualRestClient.class, RestClient.class})
public class ActualResRestClientTest {

private static final String REQUEST_URI = "something";

@InjectMocks
public ActualRestClient testee;

@Mock
private RestTemplate restTemplate;


@Test(expected = ServerException.class)
public void sendPostRequestWithResponseBody_throwsServerException() throws Exception {

    HttpServerErrorException httpServerErrorException = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
    when(restTemplate.exchange(Mockito.any(URI.class), eq(HttpMethod.POST), Mockito.any(), eq(FetchFileRequest.class))).thenThrow(httpServerErrorException);

    testee.sendFetchFileRequest(new URI(REQUEST_URI), new FetchFileRequest());
 }
}

ClientException и ServerException - это исключения, созданные мной путем расширения класса Exception. Моя проблема в том, что в классе RestClient перехватывается другое исключение (сообщение: «URI не является абсолютным») вместо HttpServerErrorException, и я не могу понять, почему. Спасибо!

вам необходимо передать действительный URI вашему методу sendFetchFileRequest. потому что конструктор URI проверит ввод строки

Lino 10.08.2018 12:58

@Lino Хороший момент, я пропустил это, когда писал свой ответ. Но теперь учтите это.

GhostCat 10.08.2018 13:10

Я пробовал это, спасибо, @Lino, но дело в том, что я хотел, чтобы это работало, независимо от того, какой URL.

B. Bal 10.08.2018 13:15

Как правило, ловить Exception - плохая идея, если вы действительно не вызываете метод, который throws Exception, и вы не можете его распространить. Вы можете поймать наиболее конкретное исключение.

Andy Turner 10.08.2018 13:38
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
3 924
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Как уже выразился комментатор: создание new URI("something") уже бросает вам вызов. Но даже если вы передадите «действительный» URI, ваш код не будет работать, поскольку с вашей стороны возникло неправильное представление. Понимаете:

RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);

Этот код находится в метод вашего тестируемого класса. Но @InjectMocks работает только для поля классов.

Другими словами: когда ваш производственный код запускается, создается новый (совершенно другой экземпляр ** ResponseTemplate. И поэтому ваша фиктивная спецификация не имеет значения, потому что метод не вызывается в вашем макете в первую очередь.

Два варианта:

  • превратите эту локальную переменную в поле вашего тестируемого класса (тогда инъекция должна работать)
  • или, поскольку вы уже используете PowerMock (ito), вы мог используете эту фиктивную структуру для перехвата этого вызова new().

Я предлагаю вам лучше использовать первый вариант и вообще не использовать расширение PowerMock (ito)!

Была еще одна проблема. RestTemplate имеет множество методов "обмена" с разными подписями ... Mockito НЕ выбрал правильный.

B. Bal 10.08.2018 15:19

Отрежу на сегодня а точнее попробую! Хороших выходных, дорогая :)

davidxxx 10.08.2018 19:43

Если вы собирались использовать PowerMock, вам нужно было бы вызвать метод Powermock expectNew, чтобы вернуть ваш mockRestTemplate. Лучшим решением было бы провести рефакторинг, как предлагает @GhostCat, и медленно уйти от PowerMock.

Michael Peacock 14.08.2018 16:58

@MichaelPeacock Медленно? Беги, Форест, беги!

GhostCat 14.08.2018 16:59

Другие вопросы по теме