API играет важную роль в развитии ПО. Поэтому правильное автоматизированное тестирование API становится всё более необходимым. Существует множество различных инструментов, которые помогут вам в написании автоматизированных тестов. Эта статья расскажет об использовании одного из самых популярных инструментов для этой задачи: REST Assured.
REST Assured — это библиотека Java, предназначенная для тестирования RESTful API. Вы также можете копировать и использовать примеры кода из этой статьи.
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Начало работы: Конфигурация
Чтобы начать работу с REST Assured, просто внесите его в качестве зависимости в свой проект. Если вы используете Maven, добавьте следующую запись в ваш pom.xml:
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>3.0.2</version>
<scope>test</scope>
</dependency>
И для Gradle:
testCompile 'io.rest-assured:rest-assured:3.0.2'
REST Assured можно использовать с фреймворками для модульного тестирования, такими как JUnit и TestNG. В примерах из этой статьи REST Assured использовался вместе с TestNG.
После настройки импорта REST Assured, добавьте следующие статические «импорты» в ваш тестовый класс:
import static io.restassured.RestAssured.*; import static org.hamcrest.Matchers.*;
Первый тест: Понимание синтаксиса
В статье будет тестироваться API базы данных автогонок Ergast, который можно найти здесь. Этот API предоставляет данные, связанные с гонками Формулы-1, гонщиками, трассами и многим другим.
Ниже приведён тест, написанный с помощью REST Assured, который получает список трасс 2017 года в формате JSON и проверяет, есть ли в списке 20 трасс:
@Test
public void test_NumberOfCircuitsFor2017Season_ShouldBe20() {
given().
when().
get("http://ergast.com/api/f1/2017/circuits.json").
then().
assertThat().
body("MRData.CircuitTable.Circuits.circuitId",hasSize(20));
}
Обратите внимание, что API, используемый REST Assured, поддерживает синтаксис Given/When/Then. Благодаря чему тест легко читается и выполняет все необходимые действия всего в одной строке кода.
Матчер hasSize() в Hamcrest подсчитывает количество трасс — вот почему вам нужно было добавить Hamcrest в качестве статического импорта. Библиотека Hamcrest содержит набор матчеров, которые позволяют создавать верификации всех видов, сохраняя их читабельность.
В верификационной части теста выполняется следующее:
- Запоминает (JSON) ответ на запрос API.
- Запрашивает все элементы с именем
circuitId, используя выражениеGroovy GPath "MRData.CircuitTable.Circuits.circuitId". - Проверяет, что полученное количество элементов
circuitIdравно 20.
В Hamcrest существуют матчеры для большого количества различных проверок, включая equalTo() для равенства, lessThan() и greaterThan() для сравнения, hasItem() для проверки, содержит ли база данных запрашиваемый элемент, и многие другие. Полный список матчеров приведен в документации библиотеки Hamcrest.
Валидация данных ответа
С помощью REST Assured вы можете не только проверить содержимое тела ответа, но и проконтролировать его технические характеристики, такие как код состояния HTTP, формат содержимого ответа и т. д. В приведенном ниже примере проверяется следующее:
- Код состояния ответа — 200.
- Формат содержимого ответа (указывает получателю, как интерпретировать тело ответа) —
"application/json". - Значение заголовка ответа
"Content-Length"равно 4567.
@Test
public void test_ResponseHeaderData_ShouldBeCorrect() {
given().
when().
get("http://ergast.com/api/f1/2017/circuits.json").
then().
assertThat().
statusCode(200).
and().
contentType(ContentType.JSON).
and().
header("Content-Length",equalTo("4567"));
}
Этот пример также показывает, как легко объединить проверки в удобный и читаемый вид с помощью метода and(). Единственная функция этого метода — делать код более простым к восприятию.
Параметризованные тесты
Часто возникает необходимость проводить один и тот же тест с различными наборами данных. Вместо того чтобы писать новый тест для каждого набора, вы можете создать параметризованный тест (parameterized test). И передать ему столько тестовых данных, сколько требуется для успешного покрытия теста.
RESTful API поддерживают два различных типа параметров:
- Параметры запроса (query parameters). Они добавляются в конце конечной точки RESTful API и их можно отличить по знаку вопроса перед ними. Например, в конечной точке
http://md5.jsontest.com/?text=test«text» является параметром запроса (со значением «test»). - Параметры пути (path parameters). Они являются частью конечной точки RESTful API. Например, в конечной точке
http://ergast.com/api/f1/2017/circuits.json, «2017» — это значение параметра пути. Попробуйте заменить его на «2016» и посмотрите, что произойдет (подсказка: тест должен провалиться, так как в 2016 году была 21 гонка Формулы-1, а не 20).
REST Assured может работать с обоими типами параметров. Сначала посмотрим, как можно задать и использовать параметр запроса из примера выше:
@Test
public void test_Md5CheckSumForTest_ShouldBe098f6bcd4621d373cade4e832627b4f6() {
String originalText = "test";
String expectedMd5CheckSum = "098f6bcd4621d373cade4e832627b4f6";
given().
param("text",originalText).
when().
get("http://md5.jsontest.com").
then().
assertThat().
body("md5",equalTo(expectedMd5CheckSum));
}
Как видите, использовать параметры запроса в REST Assured очень просто, для этого нужно указать их имя и значение с помощью метода param(). Параметры пути задаются аналогичным образом:
@Test
public void test_NumberOfCircuits_ShouldBe20_Parameterized() {
String season = "2017";
int numberOfRaces = 20;
given().
pathParam("raceSeason",season).
when().
get("http://ergast.com/api/f1/{raceSeason}/circuits.json").
then().
assertThat().
body("MRData.CircuitTable.Circuits.circuitId",hasSize(numberOfRaces));
}
Вместо param() параметры пути определяются с помощью метода pathParam(). Кроме того, вам необходимо определить, какая часть конечной точки представляет собой переменную path, что делается с помощью фигурных скобок. Таким же образом можно создать более одного параметра пути и даже объединить эти параметры в одном запросе.
Теперь, когда мы параметризовали тест, наполнить его набором тестовых данных — несложная задача. В TestNG достаточно создать объект DataProvider, содержащий необходимые тестовые данные, в нашем случае — это набор данных, содержащий годы и количество гонок Формулы-1 в каждом из них:
@DataProvider(name="seasonsAndNumberOfRaces")
public Object[][] createTestDataRecords() {
return new Object[][] {
{"2017",20},
{"2016",21},
{"1966",9}
};
}
Затем просто передаем тестовые данные параметризованному тесту с помощью основных методов REST Assured:
@Test(dataProvider="seasonsAndNumberOfRaces")
public void test_NumberOfCircuits_ShouldBe_DataDriven(String season, int numberOfRaces) {
given().
pathParam("raceSeason",season).
when().
get("http://ergast.com/api/f1/{raceSeason}/circuits.json").
then().
assertThat().
body("MRData.CircuitTable.Circuits.circuitId",hasSize(numberOfRaces));
}
Теперь вы можете добавлять, удалять или обновлять отдельные тест-кейсы, просто создавая или изменяя соответствующую запись.
Доступ к защищенным API
Часто API защищены с помощью механизма аутентификации. REST Assured поддерживает базовую, дайджест и OAuth аутентификацию. Вот пример вызова RESTful API, защищённого с помощью базовой аутентификации (т. е. пользователь этого API должен предоставлять правильное имя и пароль при каждом вызове API):
@Test
public void test_APIWithBasicAuthentication_ShouldBeGivenAccess() {
given().
auth().
preemptive().
basic("username", "password").
when().
get("http://path.to/basic/secured/api").
then().
assertThat().
statusCode(200);
}
Получить доступ к API, защищенному OAuth2, просто, если у вас есть действительный токен аутентификации:
@Test
public void test_APIWithOAuth2Authentication_ShouldBeGivenAccess() {
given().
auth().
oauth2(YOUR_AUTHENTICATION_TOKEN_GOES_HERE).
when().
get("http://path.to/oath2/secured/api").
then().
assertThat().
statusCode(200);
}
Передача значений между тестами
Часто при тестировании RESTful API возникает необходимость в создании более сложных тест-кейсов. В них требуется получить значение из ответа одного вызова API и повторно использовать его в следующем вызове. Это можно сделать с помощью метода extract(). В качестве примера приведён сценарий, который извлекает идентификатор первой трассы сезона 2017 года и использует его для получения и проверки дополнительной информации об этой трассе (в данном случае трасса находится в Австралии):
@Test
public void test_ScenarioRetrieveFirstCircuitFor2017SeasonAndGetCountry_ShouldBeAustralia() {
// First, retrieve the circuit ID for the first circuit of the 2017 season
String circuitId = given().
when().
get("http://ergast.com/api/f1/2017/circuits.json").
then().
extract().
path("MRData.CircuitTable.Circuits.circuitId[0]");
// Then, retrieve the information known for that circuit and verify it is located in Australia
given().
pathParam("circuitId",circuitId).
when().
get("http://ergast.com/api/f1/circuits/{circuitId}.json").
then().
assertThat().
body("MRData.CircuitTable.Circuits.Location[0].country",equalTo("Australia"));
}
Повторное использование проверок с помощью ResponseSpecBuilder
Ещё один способ улучшить многократное использование ваших тестов RESTful API — это повторное использование определённых проверок. Например, если вы хотите удостовериться, что все получаемые ответы имеют код состояния, равный 200, а их формат соответствует "application/json". Проверка этого для каждого теста может быть очень утомительна.
REST Assured поддерживает повторное использование определенных проверок с помощью механизма ResponseSpecBuilder.
Вот пример того, как создать повторно используемую ResponseSpecification, проверяющую код состояния и формат содержимого ответов:
ResponseSpecification checkStatusCodeAndContentType =
new ResponseSpecBuilder().
expectStatusCode(200).
expectContentType(ContentType.JSON).
build();
Test
public void test_NumberOfCircuits_ShouldBe20_UsingResponseSpec() {
given().
when().
get("http://ergast.com/api/f1/2017/circuits.json").
then().
assertThat().
spec(checkStatusCodeAndContentType).
and().
body("MRData.CircuitTable.Circuits.circuitId",hasSize(20));
}
Другие возможности REST Assured
Помимо уже описанных, REST Assured предлагает ряд других полезных функций:
- Возможность (де-) сериализации Java-объектов (POJO). Это позволяет вам перевести свойства и значения Java-объекта, в JSON или XML документ и наоборот. Затем этот документ можно отправить с помощью метода POST.
- Сохранение запросов и ответов. Это полезно, если нужно просмотреть ответы API для создания соответствующих проверок, или убедиться, что отправленный запрос корректен.
- REST Assured поставляется с модулем Spring Mock MVC, позволяющим писать тесты для контроллеров Spring, используя синтаксис REST Assured.
Перевод статьи Bas Dijkstra «How to perform API testing with REST Assured».
