Цель состоит в том, чтобы дать представление о технологиях и написать несколько тестов на базовую правильность. В примерах используется последняя версия REST API GitHub.
Для внутреннего приложения этот вид тестирования обычно выполняется в качестве позднего шага в процессе непрерывной интеграции, потребляя REST API после того, как он уже развернут.
При тестировании ресурса REST обычно есть несколько ортогональных обязанностей, на которых должны сосредоточиться тесты:
- код ответа HTTP
- другие заголовки HTTP в ответе
- полезная нагрузка (JSON, XML)
Каждый тест должен быть сосредоточен только на одной ответственности и включать одно утверждение. Сосредоточение внимания на четком разделении всегда имеет свои преимущества, но при проведении такого рода тестирования «черного ящика» это еще более важно, так как общая тенденция заключается в написании сложных сценариев тестирования в самом начале.
Другим важным аспектом интеграционных тестов является соблюдение принципа единого уровня абстракции — логика в тесте должна быть написана на высоком уровне. Такие детали, как создание запроса, отправка HTTP-запроса на сервер, работа с IO и т. Д., Должны выполняться не встроенно, а с помощью служебных методов.
Тестирование кода ответа HTTP
01
02
03
04
05
06
07
08
09
10
11
12
13
|
@Test public void givenUserDoesNotExists_whenUserInfoIsRetrieved_then404IsReceived() throws ClientProtocolException, IOException{ // Given String name = randomAlphabetic( 8 ); // When HttpResponse httpResponse = httpClient.execute( request ); // Then RestAssert.assertResponseCodeIs( httpResponse, 404 ); } |
Это довольно простой тест, который проверяет, работает ли базовый «счастливый путь», без особой сложности для набора тестов. Если по какой-либо причине он не работает, то нет необходимости искать какой-либо другой тест для этого URL, пока он не будет исправлен. Поскольку проверка кода ответа является одним из наиболее распространенных утверждений комплекта тестирования интеграции, используется настраиваемое утверждение .
1
2
3
4
5
|
public static void assertResponseCodeIs ( final HttpResponse response, final int expectedCode ){ final int statusCode = httpResponse.getStatusLine().getStatusCode(); assertEquals( expectedCode, statusCode ); } |
Тестирование других заголовков ответа HTTP
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Test public void givenRequestWithNoAcceptHeader_whenRequestIsExecuted_thenDefaultResponseContentTypeIsJson() throws ClientProtocolException, IOException{ // Given String jsonMimeType = "application/json" ; // When HttpResponse response = this .httpClient.execute( request ); // Then String mimeType = EntityUtils.getContentMimeType( response.getEntity() ); assertEquals( jsonMimeType, mimeType ); } |
Это гарантирует, что ответ при запросе данных пользователя на самом деле является JSON. Существует логическая последовательность тестируемой функциональности — сначала код ответа, чтобы убедиться, что запрос был в порядке, затем тип MIME-запроса и только потом проверка, что фактический JSON верен.
Тестирование полезной нагрузки JSON HTTP-ответа
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
@Test public void givenUserExists_whenUserInformationIsRetrieved_thenRetrievedResourceIsCorrect() throws ClientProtocolException, IOException{ // Given // When HttpResponse response = new DefaultHttpClient().execute( request ); // Then GitHubUser resource = RetrieveUtil.retrieveResourceFromResponse( response, GitHubUser. class ); assertThat( "eugenp" , Matchers.is( resource.getLogin() ) ); } |
В этом случае я знаю, что представлением ресурсов GitHub по умолчанию является JSON, но обычно заголовок Content-Type ответа должен проверяться вместе с заголовком Accept запроса — клиент запрашивает определенный тип представления через Accept, который Сервер должен соблюдать.
Утилиты для тестирования
Вот утилиты, которые позволяют тестам оставаться на более высоком уровне абстракции:
— украсить HTTP-запрос полезной нагрузкой JSON (или непосредственно POJO):
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
|
public static < T >HttpEntityEnclosingRequest decorateRequestWithResource ( final HttpEntityEnclosingRequest request, final T resource ) throws IOException{ Preconditions.checkNotNull( request ); Preconditions.checkNotNull( resource ); final String resourceAsJson = JsonUtil.convertResourceToJson( resource ); return JsonUtil.decorateRequestWithJson( request, resourceAsJson ); } public static HttpEntityEnclosingRequest decorateRequestWithJson ( final HttpEntityEnclosingRequest request, final String json ) throws UnsupportedEncodingException{ Preconditions.checkNotNull( request ); Preconditions.checkNotNull( json ); request.setHeader( HttpConstants.CONTENT_TYPE_HEADER, "application/json" ); request.setEntity( new StringEntity( json ) ); return request; } |
— получить полезную нагрузку JSON (или непосредственно POJO) из ответа HTTP:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
public static String retrieveJsonFromResponse( final HttpResponse response ) throws IOException{ Preconditions.checkNotNull( response ); return IOUtils.toString( response.getEntity().getContent() ); } public static < T >T retrieveResourceFromResponse ( final HttpResponse response, final Class< T > clazz ) throws IOException{ Preconditions.checkNotNull( response ); Preconditions.checkNotNull( clazz ); final String jsonFromResponse = retrieveJsonFromResponse( response ); return ConvertUtil.convertJsonToResource( jsonFromResponse, clazz ); } |
— утилиты преобразования в и из объекта Java (POJO) в JSON:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
public static < T >String convertResourceToJson( final T resource ) throws IOException{ Preconditions.checkNotNull( resource ); return new ObjectMapper().writeValueAsString( resource ); } public static < T >T convertJsonToResource ( final String json, final Class< T > clazzOfResource ) throws IOException{ Preconditions.checkNotNull( json ); Preconditions.checkNotNull( clazzOfResource ); return new ObjectMapper().readValue( json, clazzOfResource ); } |
зависимости
Утилиты и тесты используют следующие библиотеки, все доступные в Maven central:
Вывод
Это только одна часть того, каким должен быть полный комплект тестирования интеграции. Тесты направлены на обеспечение базовой правильности API REST, не вдаваясь в более сложные сценарии, обнаруживаемость API, использование различных представлений для одного и того же ресурса или других более сложных областей. Я расскажу об этом в следующем посте, а пока ознакомьтесь с полным проектом на github .
Ссылка: Введение в интеграционное тестирование Java для RESTful API от нашего партнера JCG Юджина Параскива в блоге baeldung .
- Веб-сервисы RESTful с RESTeasy JAX-RS на Tomcat 7 — проект Eclipse и Maven
- Spring 3 RESTful веб-сервисы
- Тестирование Spring 3 с помощью JUnit 4 — ContextConfiguration и AbstractTransactionalJUnit4SpringContextTests
- Покрытие кода модульными и интеграционными тестами
- Интеграция jqGrid, REST, AJAX и Spring MVC
- Правила в JUnit 4.9 (бета 3)
- Список учебных пособий по Java и Android