У меня проблема при попытке протестировать класс, представляющий 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, и я не могу понять, почему. Спасибо!
@Lino Хороший момент, я пропустил это, когда писал свой ответ. Но теперь учтите это.
Я пробовал это, спасибо, @Lino, но дело в том, что я хотел, чтобы это работало, независимо от того, какой URL.
Как правило, ловить Exception
- плохая идея, если вы действительно не вызываете метод, который throws Exception
, и вы не можете его распространить. Вы можете поймать наиболее конкретное исключение.
Как уже выразился комментатор: создание new URI("something")
уже бросает вам вызов. Но даже если вы передадите «действительный» URI, ваш код не будет работать, поскольку с вашей стороны возникло неправильное представление. Понимаете:
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
Этот код находится в метод вашего тестируемого класса. Но @InjectMocks работает только для поля классов.
Другими словами: когда ваш производственный код запускается, создается новый (совершенно другой экземпляр ** ResponseTemplate. И поэтому ваша фиктивная спецификация не имеет значения, потому что метод не вызывается в вашем макете в первую очередь.
Два варианта:
new()
.Я предлагаю вам лучше использовать первый вариант и вообще не использовать расширение PowerMock (ito)!
Была еще одна проблема. RestTemplate имеет множество методов "обмена" с разными подписями ... Mockito НЕ выбрал правильный.
Отрежу на сегодня а точнее попробую! Хороших выходных, дорогая :)
Если вы собирались использовать PowerMock, вам нужно было бы вызвать метод Powermock expectNew, чтобы вернуть ваш mockRestTemplate. Лучшим решением было бы провести рефакторинг, как предлагает @GhostCat, и медленно уйти от PowerMock.
вам необходимо передать действительный
URI
вашему методуsendFetchFileRequest
. потому что конструкторURI
проверит ввод строки