«1. Введение

REST-assured был разработан для упрощения тестирования и проверки REST API, и на него сильно повлияли методы тестирования, используемые в динамических языках, таких как Ruby и Groovy.

Библиотека имеет надежную поддержку HTTP, начиная, конечно же, с глаголами и стандартными операциями HTTP, но также выходя далеко за рамки этих основ.

В этом руководстве мы собираемся изучить REST-assured и будем использовать Hamcrest для утверждения. Если вы еще не знакомы с Hamcrest, вам следует сначала освежить в памяти учебник: Тестирование с помощью Hamcrest.

Кроме того, чтобы узнать о более продвинутых вариантах использования REST-assured, ознакомьтесь с другими нашими статьями:

    REST-assured с Groovy JSON Schema Validation с REST-assured Parameters, Headers and Cookies с REST-assured ~~ ~ Теперь давайте рассмотрим простой пример.

2. Простой пример теста

Прежде чем мы начнем, давайте удостоверимся, что наши тесты имеют следующие статические импорты:

Нам это понадобится, чтобы сделать тесты простыми и иметь легкий доступ к основным API. .

io.restassured.RestAssured.*
io.restassured.matcher.RestAssuredMatchers.*
org.hamcrest.Matchers.*

Теперь давайте начнем с простого примера — базовой системы ставок, предоставляющей некоторые данные для игр:

Допустим, это ответ JSON на обращение к локально развернутому API — http: //локальный:8080/события?id=390. :

{
    "id": "390",
    "data": {
        "leagueId": 35,
        "homeTeam": "Norway",
        "visitingTeam": "England",
    },
    "odds": [{
        "price": "1.30",
        "name": "1"
    },
    {
        "price": "5.25",
        "name": "X"
    }]
}

Давайте теперь воспользуемся REST-assured для проверки некоторых интересных особенностей ответа JSON:

Итак, что мы сделали здесь — мы проверили, что вызов конечной точки /events?id=390 отвечает телом, содержащим строку JSON, чей номер лиги объекта данных равен 35.

@Test
public void givenUrl_whenSuccessOnGetsResponseAndJsonHasRequiredKV_thenCorrect() {
   get("/events?id=390").then().statusCode(200).assertThat()
      .body("data.leagueId", equalTo(35)); 
}

Давайте рассмотрим более интересный пример. Допустим, вы хотите убедиться, что в массиве шансов есть записи с ценами 1,30 и 5,25: .xml файл:

Чтобы получить последнюю версию, перейдите по этой ссылке. REST-assured использует возможности сопоставителей Hamcrest для выполнения своих утверждений, поэтому мы также должны включить эту зависимость:

@Test
public void givenUrl_whenJsonResponseHasArrayWithGivenValuesUnderKey_thenCorrect() {
   get("/events?id=390").then().assertThat()
      .body("odds.price", hasItems("1.30", "5.25"));
}

Последняя версия всегда будет доступна по этой ссылке.

4. Проверка анонимного корня JSON

<dependency>
    <groupId>io.rest-assured</groupId>
    <artifactId>rest-assured</artifactId>
    <version>3.3.0</version>
    <scope>test</scope>
</dependency>

Рассмотрим массив, состоящий из примитивов, а не объектов: действительные данные JSON.

<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-all</artifactId>
    <version>2.1</version>
</dependency>

Мы можем запустить проверку в таком сценарии, используя символ $ или пустую строку ( «œ» ) в качестве пути. Предположим, что мы предоставляем указанный выше сервис через http://localhost:8080/json, тогда мы можем проверить его с помощью REST-assured:

или так:

5. Плавающие и двойные значения ~ ~~ Когда мы начинаем использовать REST-assured для тестирования наших REST-сервисов, нам нужно понимать, что числа с плавающей запятой в ответах JSON сопоставляются с примитивным типом float.

[1, 2, 3]

Использование типа float не взаимозаменяемо с double, как это имеет место во многих сценариях в java.

В качестве примера можно привести следующий ответ:

when().get("/json").then().body("$", hasItems(1, 2, 3));

предположим, что мы выполняем следующую проверку значения ck:

when().get("/json").then().body("", hasItems(1, 2, 3));

Этот тест завершится ошибкой, даже если проверяемое значение равно значение в ответе. Это потому, что мы сравниваем с двойным, а не с плавающей запятой.

Чтобы заставить его работать, мы должны явно указать операнд для метода сопоставления equalTo как число с плавающей запятой, например так:

6. Указание метода запроса

Обычно мы выполняем запрос вызов метода, такого как get(), соответствующего методу запроса, который мы хотим использовать.

{
    "odd": {
        "price": "1.30",
        "ck": 12.2,
        "name": "1"
    }
}

Кроме того, мы также можем указать глагол HTTP, используя метод request():

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2));

Приведенный выше пример эквивалентен прямому использованию get().

Точно так же мы можем отправлять запросы HEAD, CONNECT и OPTIONS:

get("/odd").then().assertThat().body("odd.ck", equalTo(12.2f));

Запрос POST также имеет аналогичный синтаксис, и мы можем указать тело с помощью методов with() и body().

Поэтому, чтобы создать новый Odd, отправив запрос POST:

Объект Odd, отправленный как тело, будет автоматически преобразован в JSON. Мы также можем передать любую строку, которую хотим отправить, в качестве тела POST.

@Test
public void whenRequestGet_thenOK(){
    when().request("GET", "/users/eugenp").then().statusCode(200);
}

«7. Конфигурация значений по умолчанию

Мы можем настроить множество значений по умолчанию для тестов:

@Test
public void whenRequestHead_thenOK() {
    when().request("HEAD", "/users/eugenp").then().statusCode(200);
}

Здесь мы устанавливаем базовый URI и порт для наших запросов. Помимо этого, мы также можем настроить базовый путь, корневой каталог и аутентификацию.

Примечание: мы также можем восстановить стандартные значения по умолчанию, гарантированные REST, используя:

@Test
public void whenRequestedPost_thenCreated() {
    with().body(new Odd(5.25f, 1, 13.1f, "X"))
      .when()
      .request("POST", "/odds/new")
      .then()
      .statusCode(201);
}

8. Измерение времени отклика

Давайте посмотрим, как мы можем измерить время отклика, используя time() и timeIn( ) методы объекта Response:

Обратите внимание, что:

@Before
public void setup() {
    RestAssured.baseURI = "https://api.github.com";
    RestAssured.port = 443;
}

time() используется для получения времени ответа в миллисекундах timeIn() используется для получения времени ответа в указанной единице времени

8.1. Проверить время отклика

RestAssured.reset();

Мы также можем проверить время отклика — в миллисекундах — с помощью простого long Matcher:

Если мы хотим проверить время отклика в другой единице времени, то мы будем использовать сопоставитель time() со вторым параметром TimeUnit:

@Test
public void whenMeasureResponseTime_thenOK() {
    Response response = RestAssured.get("/users/eugenp");
    long timeInMS = response.time();
    long timeInS = response.timeIn(TimeUnit.SECONDS);
    
    assertEquals(timeInS, timeInMS/1000);
}

9. Проверка ответа XML

    Он может проверять не только ответ JSON, но и XML.

Предположим, мы делаем запрос к http://localhost:8080/employees и получаем следующий ответ:

Мы можем проверить, что имя — Джейн, вот так:

@Test
public void whenValidateResponseTime_thenSuccess() {
    when().get("/users/eugenp").then().time(lessThan(5000L));
}

~~ ~ Мы также можем проверить, что все значения соответствуют нашим ожидаемым значениям, объединив сопоставители тела вместе следующим образом:

@Test
public void whenValidateResponseTimeInSeconds_thenSuccess(){
    when().get("/users/eugenp").then().time(lessThan(5L),TimeUnit.SECONDS);
}

Или используя сокращенную версию с переменными аргументами:

10. XPath для XML

Мы также может проверить наши ответы с помощью XPath. Рассмотрим приведенный ниже пример, в котором выполняется сопоставление по имени:

<employees>
    <employee category="skilled">
        <first-name>Jane</first-name>
        <last-name>Daisy</last-name>
        <sex>f</sex>
    </employee>
</employees>

XPath также допускает альтернативный способ запуска сопоставления equalTo:

@Test
public void givenUrl_whenXmlResponseValueTestsEqual_thenCorrect() {
    post("/employees").then().assertThat()
      .body("employees.employee.first-name", equalTo("Jane"));
}

11. Регистрация подробностей теста

@Test
public void givenUrl_whenMultipleXmlValuesTestEqual_thenCorrect() {
    post("/employees").then().assertThat()
      .body("employees.employee.first-name", equalTo("Jane"))
        .body("employees.employee.last-name", equalTo("Daisy"))
          .body("employees.employee.sex", equalTo("f"));
}

11.1. Сведения о запросе журнала

@Test
public void givenUrl_whenMultipleXmlValuesTestEqualInShortHand_thenCorrect() {
    post("/employees")
      .then().assertThat().body("employees.employee.first-name", 
        equalTo("Jane"),"employees.employee.last-name", 
          equalTo("Daisy"), "employees.employee.sex", 
            equalTo("f"));
}

Во-первых, давайте посмотрим, как регистрировать все детали запроса с помощью log().all():

Это будет выглядеть примерно так: запрос, у нас есть метод log() в сочетании с params(), body(), headers(), cookies(), method(), path(), например, log.().params().

@Test
public void givenUrl_whenValidatesXmlUsingXpath_thenCorrect() {
    post("/employees").then().assertThat().
      body(hasXPath("/employees/employee/first-name", containsString("Ja")));
}

Обратите внимание, что другие используемые библиотеки или фильтры могут изменить то, что на самом деле отправляется на сервер, поэтому их следует использовать только для регистрации первоначальной спецификации запроса.

@Test
public void givenUrl_whenValidatesXmlUsingXpath2_thenCorrect() {
    post("/employees").then().assertThat()
      .body(hasXPath("/employees/employee/first-name[text()='Jane']"));
}

11.2. Log Response Details

Точно так же мы можем регистрировать детали ответа.

В следующем примере мы регистрируем только тело ответа:

@Test
public void whenLogRequest_thenOK() {
    given().log().all()
      .when().get("/users/eugenp")
      .then().statusCode(200);
}

Пример вывода:

Request method:	GET
Request URI:	https://api.github.com:443/users/eugenp
Proxy:			<none>
Request params:	<none>
Query params:	<none>
Form params:	<none>
Path params:	<none>
Multiparts:		<none>
Headers:		Accept=*/*
Cookies:		<none>
Body:			<none>

11.3. Записывать ответ при возникновении условия

У нас также есть возможность записывать ответ, только если произошла ошибка или код состояния соответствует заданному значению:

11.4. Журнал, если проверка не пройдена

Мы также можем записывать как запрос, так и ответ, только если наша проверка не удалась:

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

@Test
public void whenLogResponse_thenOK() {
    when().get("/repos/eugenp/tutorials")
      .then().log().body().statusCode(200);
}

12. Заключение

{
    "id": 9754983,
    "name": "tutorials",
    "full_name": "eugenp/tutorials",
    "private": false,
    "html_url": "https://github.com/eugenp/tutorials",
    "description": "The \"REST With Spring\" Course: ",
    "fork": false,
    "size": 72371,
    "license": {
        "key": "mit",
        "name": "MIT License",
        "spdx_id": "MIT",
        "url": "https://api.github.com/licenses/mit"
    },
...
}

В этом руководстве мы изучили среду с поддержкой REST и рассмотрели ее наиболее важные функции, которые мы можем использовать для тестирования наших служб RESTful и проверки их ответов.

Полную реализацию всех этих примеров и фрагментов кода можно найти в проекте GitHub с поддержкой REST.

@Test
public void whenLogResponseIfErrorOccurred_thenSuccess() {
 
    when().get("/users/eugenp")
      .then().log().ifError();
    when().get("/users/eugenp")
      .then().log().ifStatusCodeIsEqualTo(500);
    when().get("/users/eugenp")
      .then().log().ifStatusCodeMatches(greaterThan(200));
}

«

We can also log both request and response only if our validation failed:

@Test
public void whenLogOnlyIfValidationFailed_thenSuccess() {
    when().get("/users/eugenp")
      .then().log().ifValidationFails().statusCode(200);

    given().log().ifValidationFails()
      .when().get("/users/eugenp")
      .then().statusCode(200);
}

In this example, we want to validate that the status code is 200. Only if this fails, the request and response will be logged.

12. Conclusion

In this tutorial, we have explored the REST-assured framework and looked at its most important features which we can use to test our RESTful services and validate their responses.

The full implementation of all these examples and code snippets can be found in the REST-assured GitHub project.