Перевод статьи «API Testing Showdown: Postman vs Pytest. Part 1».
Когда речь заходит об автоматизации тестирования API, в ход идет множество инструментов. Фреймворк pytest в сочетании с библиотекой requests – один из самых популярных вариантов на сегодняшний день. В то же время у нас есть популярный HTTP-клиент для тестирования API – Postman. В нем даже присутствует функция написания автотестов – благодаря встроенному JS-движку.
Это первая часть нашего пособия. В ней мы рассмотрим, как вышеупомянутые инструменты справляются с тестами начального уровня, изучим систему переменных в Postman и порассуждаем о том, насколько этот клиент подходит в качестве IDE.
Друзья, поддержите нас вступлением в наш телеграм канал QaRocks. Там много туториалов, задач по автоматизации и книг по QA.
Что такое Postman?
В синем углу ринга у нас расположился Postman. Это целая платформа для разработки API, содержащая множество функций.
Postman позволяет проработать все необходимые части разработки API, включая документирование, создание прототипов и тестирование.
О последней части – тестировании – мы и поговорим.
Что такое Pytest?
В красном углу ринга находится Pytest – полнофункциональный фреймворк тестирования общего назначения на языке Python. В нем есть все, что только можно ожидать от такого типа инструментов: прогон тестов, метки, фикстуры, хуки и т.д. При этом он не является визуальным фреймворком.
“Из коробки” он подходит только для модульного тестирования. Чтобы сделать возможным тестирование REST API, нам необходимо то, что будет делать HTTP-запросы. Для этой цели будем использовать библиотеку Requests.
Небольшое замечание: далее по тексту мы будем обсуждать REST API, но те же принципы применимы и к другим протоколам.
Простой тест
Postman
Postman отлично подходит в качестве HTTP-клиента. Вам не нужно писать ни одной строки кода, чтобы увидеть ответ.
Безусловно, вам придется написать код для создания ассертов (assert). Postman использует для этого движок JavaScript.
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); });
Одна из примечательных особенностей этого инструмента – сниппеты кода. Этот небольшой тест был создан с их помощью.
Пара кликов + пара правок – и тест готов. Очень удобно для новичков!
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:
- Postman, прежде всего, является клиентом API
- Основным объектом в Postman является запрос
Автотесты – это лишь дополнение к запросам Postman, а не их основа.
Хотя это может показаться тривиальным, такой подход довольно сложен для покрытия бизнес-потоков и поддержки автотестов. В дальнейшем вы увидите, как он может все усложнить.
В то же время полноценные фреймворки (в нашем случае Pytest) ставят тесты на первый план. Тест – это основа, а запрос может происходить внутри процедуры тестирования или настройки.
Давайте углубимся в подход Postman к тестированию.
Отдельные скрипты
Существует множество скриптов, которые можно запускать до и после выполнения запроса. Эти скрипты определяются разными уровнями иерархии рабочей области Postman.
Скрипты хранятся в отдельных местах, что значительно усложняет работу с кодом.
В интерфейсе шесть подвкладок распределены между тремя вкладками. Эти вкладки не связаны в пользовательском интерфейсе напрямую. Поэтому, когда вы нажимаете кнопку “Отправить”, вы не можете сказать, что происходит в этой иерархии. Вам придется искать среди вкладок вручную. И все может стать еще сложнее, если мы будем использовать унаследованные папки…
…или попытаемся создать тестовый скрипт из нескольких запросов.
Что происходило с этой переменной?
Рассмотрим базовый CRUD.
Предположим, у нас есть переменная new_world_name
, полученная из хранилища на уровне коллекции. В этом случае мы не можем сказать, когда была создана эта переменная и что происходило с ней на предыдущих шагах, не щелкнув предыдущие шаги и не просмотрев каждый пре-/постскрипт. А что, если мы захотим переименовать эту переменную?
А как насчет модулей Python?
“Папки и тестовые скрипты? Но ведь в Python все то же самое!” – могут сказать некоторые из вас. На самом деле, не совсем так. Модуль Pytest содержит тесты, а не запросы, со склеенными между собой скриптами. Вы можете легко увидеть, что происходит в тесте, не перескакивая с одного запроса на другой.
Предположим, ваш код распределен между несколькими модулями. В этом случае вы легко узнаете, как создается переменная и что происходит в тестовой настройке – благодаря заметному импорту и фикстурам в Pytest. Переименование переменных и рефакторинг кода в данном случае выглядит намного проще.
Области видимости и уровни переменных
Переменная в 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);
Результат:
Довольно неудобно, не так ли? Посмотрим, как это может еще больше усложнить ситуацию.
Вы можете попробовать сделать это самостоятельно: коллекция.
Конечно, в 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);
Рассказываю, почему. Основное назначение переменных – вставка их в 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);
Демо-коллекция находится здесь.
Отладка
Именно так мы должны производить отладку кода в Postman.
console.log(aaa); console.warn(bbb); console.error(ccc);
Помните красную точку останова, которая обычно используется для приостановки выполнения теста в вашей любимой IDE?
Забудьте о ней: разработчики Postman официально хотят, чтобы вы выполняли отладку через логирование переменных.
Надо отдать должное Postman, его журналы консоли впечатляют.
Но они все равно не могут заменить старые добрые точки останова.
Если вы все же надеетесь увидеть эту функцию в будущем, то я заранее вас разочарую. Песочница, которую использует Postman, запрещает реализацию этой возможности.
Сторонние IDE и редакторы кода
Можем ли мы использовать сторонние решения для имитации работы IDE?
Экспорт коллекций
Самый простой способ решить проблемы рефакторинга — экспортировать коллекцию.
После этого вы можете использовать любой текстовый редактор, который вам нравится. Конечно, это не самый удобный способ работы с кодом.
- Его трудно читать и легко сломать
- Нет кнопки “Запустить”
- Вам придется импортировать коллекцию назад и надеяться на лучшее после внесения изменений
- Вам придется каждый раз выполнять все вышеупомянутые действия по экспорту/импорту
Postman Local
Postman Local – это неофициальный инструмент, позволяющий производить различные манипуляции с коллекциями. Он загружает и выгружает коллекции через Postman API и хранит запросы и скрипты локально в папке, что существенно упрощает работу.
Плюсы:
- Код чище и разделен интуитивно, что гораздо лучше, чем необработанные экспортированные файлы.
- Вы можете вызывать код JS из любого места. Утилита автоматически добавит его в запросы. Конечно, это не обычный импорт JS, но это лучше, чем шаблонный код, который вы обычно распределяете по коллекциям.
Минусы:
- Точки останова отсутствуют.
- Кнопка запуска отсутствует. Вам все равно придется преобразовать отдельные файлы в коллекцию для последующего запуска.
- Переменные окружения Postman не интегрированы по умолчанию.
- Проект развивается медленно.
Я рекомендую попробовать Postman Local, если вы являетесь ярым поклонником Postman. Однако, по моему мнению, он не может заменить Pytest.
Модули и импорт
Какая вещь есть (почти) в любом языке программирования? Импорт. Он позволяет нам повторно использовать старый код, сохраняя его чистоту. Вы всегда можете отследить, откуда этот класс и как была создана эта переменная. Есть ли у нас что-то подобное в Postman? Нет.
Расширение Postman VS Code
Когда я впервые увидел анонс, я подумал: “Ух ты, это, наверное, что-то новое!”. К сожалению, это не так. Это просто реализация обрезанного интерфейса Postman внутри VS Code.
По сути это один и тот же инструмент. Он не может облегчить работу. Он даже может усложнить ее, так как многие функции здесь остались без внимания. Вероятно, в будущем появится возможность использовать больше IDE-вещей. Пока же Postman Local, созданный энтузиастами, выглядит гораздо более удобным и полезным.
Заключение
Оба инструмента, и Postman, и Pytest, подходят для простейшего автотестирования. Но когда вы начинаете писать код в Postman, вы сталкиваетесь с определенными трудностями. Одна из них – переменные. Вы не можете использовать локальную переменную в двух разных скриптах. Все переменные на уровнях выше локального имеют тип данных string. Это заставляет вас проходить через циклы сохранения-загрузки и загрузки-преобразования.
В следующей части мы рассмотрим, как можно реализовать процедуры установки/демонтажа в этих инструментах.
Пингбэк: Тестирование API: Postman VS Pytest, часть 2
Пингбэк: Большой учебник по Postman