Разделы портала

Онлайн-тренинги

.
Создание тестов API на JavaScript при помощи Pactum
10.10.2022 00:00

Автор: Баз Дейкстра (Bas Dijkstra)
Оригинал статьи
Перевод: Ольга Алифанова

 Я часто говорю себе (а также участникам моих тренингов), что JavaScript не очень-то со мной дружит. Возможно, проблема во мне, возможно, в JavaScript, но по какой-то причине я не могу вникнуть в этот язык. Университетское воспитание на куда более жестких языках (особенно Java), возможно, приложило к этому руку.

Нельзя, однако, отрицать, что JavaScript – популярный язык, и спрос на автоматизацию на нем довольно высок. Поэтому я решил, что будет хорошей идеей потратить время на исследование языка и доступные нынче инструменты.

Так как множество моих технических статей в той или иной степени посвящено тестированию API (включая имитацию API и контрактное тестирование), а ранее меня не впечатлили библиотеки для тестирования API в JavaScript, я решил, что было бы неплохо взять это за точку отсчета.

Я большой поклонник API-библиотек вроде REST Assured для Java и requests для Python, так как с их помощью очень легко писать тесты API.

Аналогично простая в использовании библиотека JavaScript была мне не знакома до тех пор, пока кто-то на LinkedIn не написал статью про Pactum (к сожалению, не могу найти оригинальный пост). Выглядело это неплохо, поэтому я решил проверить, как оно в деле.

Конечно, еще помогло то, что я обязался сделать доклад и живое демо по API-тестированию на JavaScript для группы студентов-тестировщиков. Ничто не заставляет меня изучать что-то новое так, как обязанность говорить публично.

Судя по документации, Pactum вроде бы способен на довольно-таки многое. Интеграционное тестирование, имитация API, тестирование контрактов… Все это там есть. В этой статье я сконцентрируюсь на возможностях библиотеки для тестировании API (интеграционного тестирования), но, возможно, в будущем исследую другие функции Pactum и сделаю серию статей.

Примеры, которые вы найдете в этой статье, написаны на фреймворке Jest.

Начнем с "Hello, world!" API-тестирования: выполним GET-запрос к конечно точке и проверим код статуса ответа. В Pactum это можно сделать так:

describe('Retrieving data for user with ID 1', () => {
    test('should yield HTTP status code 200', async () => {
        await pactum.spec()
            .get('http://jsonplaceholder.typicode.com/users/1')
.expectStatus(200)
});
});

pactum.spec() показывает все методы в Pactum, создающие запрос. Так как нам не нужно задавать заголовки, куки или тело запроса, мы можем напрямую вызвать HTTP GET через метод get(), передавая любую конечную точку, а затем указать ожидания от ответа. В нашем случае мы ожидаем только того, чтобы код статуса HTTP был 200, что можно проверить методом expectStatus().

Запуск этого теста (с использованием npm run test, что, в свою очередь, вызывает Jest) показывает, что тест пройден:

 

В качестве следующего шага посмотрим, можем ли мы проверить заголовок ответа, в этом случае – заголовок Content-Type:

test('should yield Content-Type header containing value "application/json"', async () => {
    await pactum.spec()
        .get('http://jsonplaceholder.typicode.com/users/1')
        .expectHeaderContains('content-type', 'application/json')
});

Метод expectHeaderContains() делает именно то, о чем заявляет: ищет заголовок ответа и проверяет, содержит ли он заданное ожидаемое значение, в данном случае application/json. Надо иметь в виду, что по какой-то причине вам нужно задавать имя заголовка в нижнем регистре. Изначально я использовал Content-Type, но тест упал, потому что не нашел соответствующий заголовок.

Если вам нужен метод для точного совпадения, используйте expectHeader().

Затем давайте посмотрим на тело ответа. Pactum очень хорошо поддерживает тела ответа JSON, а поддержка остальных вариантов (чистый текст, XML, …) ограничена построчным сравнением – это значит, что придется выполнить побольше самостоятельной работы. Наш тестируемый API возвращает данные в формате JSON, поэтому в данном случае это не проблема.

Допустим, мы хотим проверить, что имя элемента верхнего уровня равно "Leanne Graham" в ответе JSON. Это очень просто сделать, используя метод expectJsonMatch() в Pactum:

test('should yield "name" JSON body element with value "Leanne Graham"', async () => {
    await pactum.spec()
.get('http://jsonplaceholder.typicode.com/users/1')
.expectJsonMatch('name', 'Leanne Graham')
});

Первый аргумент в expectJsonMatch() – это на самом деле выражение json-query, его можно использовать и для вложенных объектов:

test('should yield "Gwenborough" as the city within the address', async () => {
    await pactum.spec()
        .get('http://jsonplaceholder.typicode.com/users/1')
        .expectJsonMatch('address.city', 'Gwenborough')
});

Как насчет POST-передачи чего-то конечной точке вместо получения и проверки данных от нее? Оказывается, это с Pactum тоже довольно просто:

describe('Posting a new post item', () => {
    test('should yield HTTP status code 201', async () => {
        let new_post = {
            "title": "My awesome new post title",
"body": "My awesome new post body",
"userId": 1
}
        await pactum.spec()
.post('http://jsonplaceholder.typicode.com/posts')
.withJson(new_post)
.expectStatus(201)
});
});

Создать содержимое JSON очень просто: нужно написать его и использовать метод withJson(), чтобы добавить его в запрос.

В качестве финального примера я часто смотрю на то, насколько легко создавать тесты, управляемые через данные, при помощи библиотеки API. Так как API часто демонстрируют бизнес-логику, и вам нужно более одной комбинации ввода и соответствующего ожидаемого вывода для правильной проверки этой логики, то тесты, управляемые через данные, очень распространены в API-тестировании.

Здесь Jest делает все сложное за нас (как JUnit делал бы в Java, а pytest в Python), давая нам механизм для таких тестов с test.each():

describe('Retrieving user data for users', () => {
    test.each(
[[1,'Leanne Graham'], [2,'Ervin Howell'], [3,'Clementine Bauch']]
)('User with ID %i has name %s', async (userId, expectedName) => {
        await pactum.spec()
.get('http://jsonplaceholder.typicode.com/users/{user}')
.withPathParams('user', userId)
.expectJsonMatch('name', expectedName) });
 });

Все, что нам остается сделать, создавая Pactum-тест – это задать параметр пути, используя метод withPathParams(), и используя его для наполнения плейсхолдера {user} в конечной точке. Механизм очень похож на аналогичную работу в Java, C# или Python, что сильно помогает мне ценить Pactum (и Jest, и даже в целом JavaScript).

Запуск этого теста вернет вот такой результат:

То, что вы увидели в этой статье – всего лишь некоторые примеры возможностей Pactum. Судя по документации, с библиотекой можно сделать намного больше, и я предвкушаю исследование его функций – особенно возможностей имитации и контрактного тестирования. Никогда не думал, что скажу это про библиотеку JavaScript…

Весь код и примеры из статьи можно найти здесь.

Обсудить в форуме