Тестирование API: Postman VS Pytest, часть 1

Перевод статьи «API Testing Showdown: Postman vs Pytest. Part 1».

Когда речь заходит об автоматизации тестирования API, в ход идет множество инструментов. Фреймворк pytest в сочетании с библиотекой requests – один из самых популярных вариантов на сегодняшний день. В то же время у нас есть популярный HTTP-клиент для тестирования API – Postman. В нем даже присутствует функция написания автотестов – благодаря встроенному JS-движку.

Это первая часть нашего пособия. В ней мы рассмотрим, как вышеупомянутые инструменты справляются с тестами начального уровня, изучим систему переменных в Postman и порассуждаем о том, насколько этот клиент подходит в качестве IDE.

Друзья, поддержите нас вступлением в наш телеграм канал QaRocks. Там много туториалов, задач по автоматизации и книг по QA.

Что такое Postman?

В синем углу ринга у нас расположился Postman. Это целая платформа для разработки API, содержащая множество функций.

инструмент для тестирования API -Postman

Postman позволяет проработать все необходимые части разработки API, включая документирование, создание прототипов и тестирование.

О последней части – тестировании – мы и поговорим.

Что такое Pytest?

В красном углу ринга находится Pytest – полнофункциональный фреймворк тестирования общего назначения на языке Python. В нем есть все, что только можно ожидать от такого типа инструментов: прогон тестов, метки, фикстуры, хуки и т.д. При этом он не является визуальным фреймворком.

“Из коробки” он подходит только для модульного тестирования. Чтобы сделать возможным тестирование REST API, нам необходимо то, что будет делать HTTP-запросы. Для этой цели будем использовать библиотеку Requests.

Небольшое замечание: далее по тексту мы будем обсуждать REST API, но те же принципы применимы и к другим протоколам.

Простой тест

Postman

Postman отлично подходит в качестве HTTP-клиента. Вам не нужно писать ни одной строки кода, чтобы увидеть ответ.

создание запроса в Postman

Безусловно, вам придется написать код для создания ассертов (assert). Postman использует для этого движок JavaScript.

пример автотеста в Postman
pm.test("Status code is 200", function () {
    pm.response.to.have.status(200);
});
pm.test("2+2=4", function () {
    var jsonData = pm.response.json();
    pm.expect(jsonData.sum).to.eql(4);
});

Одна из примечательных особенностей этого инструмента – сниппеты кода. Этот небольшой тест был создан с их помощью.

сниппеты в Postman

Пара кликов + пара правок – и тест готов. Очень удобно для новичков!

Pytest

В Pytest все, что вам нужно, – это тестовая функция и стандартный оператор assert Python (демо-версия приложения).

import requests
from requests import codes


def test_two_plus_two():
    result = requests.post("http://127.0.0.1:8000/add", data={"a": 2, "b": 2})
    assert result.status_code == codes.OK
    assert result.json()["sum"] == 4

Результаты тестов являются максимально полными сразу после установки, даже без каких-либо настроек.

Результаты тестов

На этом этапе все хорошо. Простые тесты, быстрые решения. Postman выглядит лучше в качестве графического инструмента, и у него есть удобный раздел “Результаты тестов”. С другой стороны, код Pytest чище, чем код JS в Postman. Результаты тестов Postman визуально привлекательнее, в то время как результаты Pytest гораздо подробнее. Пока что явного победителя нет.

Но давайте поразмыслим на эту тему.

Не сравниваем ли мы несравнимое?

Нам нужно остановиться и подумать, насколько корректно такое сравнение. Разве мы не сравниваем совершенно разные категории, как, например, яблоки и лапшу?

С одной стороны, да. Postman – это API-клиент/платформа API, а Pytest – фреймворк для тестирования. Существует много вариантов использования, с которыми Postman может справиться, а Pytest – нет, и наоборот.

С другой стороны, оба инструмента можно использовать для автоматизированного тестирования API.

сравнение Postman и Pytest

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

Краеугольный камень

В действительности существует две причины возникновения проблем с автотестами в Postman:

  1. Postman, прежде всего, является клиентом API
  2. Основным объектом в Postman является запрос

Автотесты – это лишь дополнение к запросам Postman, а не их основа.

Соотношение запросов и тестов в Postman

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

В то же время полноценные фреймворки (в нашем случае Pytest) ставят тесты на первый план. Тест – это основа, а запрос может происходить внутри процедуры тестирования или настройки.

Соотношение тестов и запросов с ассертами

Давайте углубимся в подход Postman к тестированию.

Отдельные скрипты

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

порядок выполнения скриптов в Postman
Древовидная структура: коллекция - папка - запрос/ответ

Скрипты хранятся в отдельных местах, что значительно усложняет работу с кодом.

Три вкладки: запрос, папка, коллекция

В интерфейсе шесть подвкладок распределены между тремя вкладками. Эти вкладки не связаны в пользовательском интерфейсе напрямую. Поэтому, когда вы нажимаете кнопку “Отправить”, вы не можете сказать, что происходит в этой иерархии. Вам придется искать среди вкладок вручную. И все может стать еще сложнее, если мы будем использовать унаследованные папки…

…или попытаемся создать тестовый скрипт из нескольких запросов.

Что происходило с этой переменной?

Рассмотрим базовый CRUD.

От запроса GET в CRUD отходит стрелка к тестовому скрипту

Предположим, у нас есть переменная new_world_name, полученная из хранилища на уровне коллекции. В этом случае мы не можем сказать, когда была создана эта переменная и что происходило с ней на предыдущих шагах, не щелкнув предыдущие шаги и не просмотрев каждый пре-/постскрипт. А что, если мы захотим переименовать эту переменную?

А как насчет модулей Python?

“Папки и тестовые скрипты? Но ведь в Python все то же самое!” – могут сказать некоторые из вас. На самом деле, не совсем так. Модуль Pytest содержит тесты, а не запросы, со склеенными между собой скриптами. Вы можете легко увидеть, что происходит в тесте, не перескакивая с одного запроса на другой.

Предположим, ваш код распределен между несколькими модулями. В этом случае вы легко узнаете, как создается переменная и что происходит в тестовой настройке – благодаря заметному импорту и фикстурам в Pytest. Переименование переменных и рефакторинг кода в данном случае выглядит намного проще.

Области видимости и уровни переменных

Переменная в Postman может быть определена на нескольких уровнях.

уровни определения переменной в Postman

Такая модель охвата соответствует духу Postman, но чревата рядом неудобств.

Локальные переменные

Допустим, у нас есть скрипт предзапроса (pre-request):

var company = 'Exness';

и последующий скрипт:

var message = 'Hello, ' + company;
console.log(message);

Оправдано ли появление Hello, Exness в консоли Postman? Нет!

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

Предварительный запрос:

var company = 'Exness';
pm.collectionVariables.set("company", company); // saving to collection variables

Тестовый скрипт:

var company = pm.collectionVariables.get("company")
var message = 'Hello, ' + company;
console.log(message);

Результат:

В консоль выводится "Hello, Exness"

Довольно неудобно, не так ли? Посмотрим, как это может еще больше усложнить ситуацию.

Вы можете попробовать сделать это самостоятельно: коллекция.

Конечно, в Pytest такой проблемы нет. Ни в теле,

def test_variable_sharing():
    company = "Exness"  # define
    requests.get(...)
    logging.log(f"Hello, {company}")  # reuse

ни в фикстурах:

@pytest.fixture
def company():
    company = "Exness"  # define
    yield company  # Pass to a test
    logging.log(f"Hello, {company}")  # Teardown

Глобальные переменные тоже работают отлично.

company = "Exness"  # define

def test_1():
    assert company == "Exness"  # 1st usage

def test_2():
    assert len(company) == 6  # 2nd usage

У всех переменных тип данных – string

Один неприятный момент: в Postman все переменные на уровнях выше локального имеют тип данных string.

Таблица с переменными и их начальными и текущими значениями
// saving collection variables as local ones

var str_text = pm.collectionVariables.get("str");
var num_text = pm.collectionVariables.get("num");
var list_text = pm.collectionVariables.get("list");
var json_text = pm.collectionVariables.get("json");

// getting type of the variables and logging them

console.log(typeof str_text);
console.log(typeof num_text);
console.log(typeof list_text);
console.log(typeof json_text);
В консоль выводятся типы переменных: все - "string"

Рассказываю, почему. Основное назначение переменных – вставка их в URL-адреса и заголовки. Но если вы хотите создать структуру, упрощающую рутинную работу, вы можете столкнуться с утомительным процессом многократного преобразования и анализа этих строк.

// saving collection variables as local ones

var list_text = pm.collectionVariables.get("list");
console.log(typeof list_text);

// parsing to get object

var true_list = JSON.parse(list_text);
console.log(typeof true_list);
console.log(typeof true_list[0]);
console.log(true_list);
Вывод в консоль результатов парсинга get-объекта

Демо-коллекция находится здесь.

Отладка

Именно так мы должны производить отладку кода в Postman.

console.log(aaa);
console.warn(bbb);
console.error(ccc);

Помните красную точку останова, которая обычно используется для приостановки выполнения теста в вашей любимой IDE?

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

Надо отдать должное Postman, его журналы консоли впечатляют.

Лог консоли

Но они все равно не могут заменить старые добрые точки останова.

Если вы все же надеетесь увидеть эту функцию в будущем, то я заранее вас разочарую. Песочница, которую использует Postman, запрещает реализацию этой возможности.

Сторонние IDE и редакторы кода

Можем ли мы использовать сторонние решения для имитации работы IDE?

Экспорт коллекций

Самый простой способ решить проблемы рефакторинга — экспортировать коллекцию.

Экспорт коллекции

После этого вы можете использовать любой текстовый редактор, который вам нравится. Конечно, это не самый удобный способ работы с кодом.

Этапы действий: экспорт коллекции, обновление кода, импорт коллекции назад
  • Его трудно читать и легко сломать
  • Нет кнопки “Запустить”
  • Вам придется импортировать коллекцию назад и надеяться на лучшее после внесения изменений
  • Вам придется каждый раз выполнять все вышеупомянутые действия по экспорту/импорту

Postman Local

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

Плюсы:

  1. Код чище и разделен интуитивно, что гораздо лучше, чем необработанные экспортированные файлы.
  2. Вы можете вызывать код JS из любого места. Утилита автоматически добавит его в запросы. Конечно, это не обычный импорт JS, но это лучше, чем шаблонный код, который вы обычно распределяете по коллекциям.

Минусы:

  1. Точки останова отсутствуют.
  2. Кнопка запуска отсутствует. Вам все равно придется преобразовать отдельные файлы в коллекцию для последующего запуска.
  3. Переменные окружения Postman не интегрированы по умолчанию.
  4. Проект развивается медленно.
График развития проекта postman-local: всплеск активности в январе 2020 года, затем  небольшие подъемы до октября 2020 г и дальнейшая пустота

Я рекомендую попробовать Postman Local, если вы являетесь ярым поклонником Postman. Однако, по моему мнению, он не может заменить Pytest.

Модули и импорт

Древовидная структура тестов в PyTest

Какая вещь есть (почти) в любом языке программирования? Импорт. Он позволяет нам повторно использовать старый код, сохраняя его чистоту. Вы всегда можете отследить, откуда этот класс и как была создана эта переменная. Есть ли у нас что-то подобное в Postman? Нет.

Расширение Postman VS Code

Когда я впервые увидел анонс, я подумал: “Ух ты, это, наверное, что-то новое!”. К сожалению, это не так. Это просто реализация обрезанного интерфейса Postman внутри VS Code.

Расширение Postman VS Code

По сути это один и тот же инструмент. Он не может облегчить работу. Он даже может усложнить ее, так как многие функции здесь остались без внимания. Вероятно, в будущем появится возможность использовать больше IDE-вещей. Пока же Postman Local, созданный энтузиастами, выглядит гораздо более удобным и полезным.

Заключение

Оба инструмента, и Postman, и Pytest, подходят для простейшего автотестирования. Но когда вы начинаете писать код в Postman, вы сталкиваетесь с определенными трудностями. Одна из них – переменные. Вы не можете использовать локальную переменную в двух разных скриптах. Все переменные на уровнях выше локального имеют тип данных string. Это заставляет вас проходить через циклы сохранения-загрузки и загрузки-преобразования.

В следующей части мы рассмотрим, как можно реализовать процедуры установки/демонтажа в этих инструментах.

2 комментария к “Тестирование API: Postman VS Pytest, часть 1”

  1. Пингбэк: Тестирование API: Postman VS Pytest, часть 2

  2. Пингбэк: Большой учебник по Postman

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *