Как стать автором
Обновить

Make It Right! Максимум пользы, минимум проблем: рекомендации по написанию API автотестов на Python

Время на прочтение17 мин
Количество просмотров11K
Всего голосов 7: ↑7 и ↓0+7
Комментарии9

Комментарии 9

Хотя и полезно, спасибо, но хотелось бы ещё и рекомендации по самим библиотекам - что и как юзать. Почему pytest а не unittest, почему классы а не функциональные тесты, что лучше factory-boy или mommy/bakery. А чего б не взять tavern или postman это наше все. Если тест интеграции с Aws брать moto/boto или писать своё. И в конце - а где авто сборщик документации тестов а'ля swagger?

  • Почему pytest вместо unittest или tavern- pytest предлагает более простой, гибкий и мощный подход к автотестированию на Python, как по мне, unittest лучше подходит для юнит-тестов, чем для автотестов.

  • Что лучше factory-boy или mommy/bakery - мне кажется, тут всё индивидуально, каждая из них имеет свои преимущества и недостатки, которые могут варьироваться в зависимости от ваших конкретных потребностей и предпочтений. 

  • Такие инструменты как postman всё-таки чаще используются для ручного тестирования и автотестировщики его используют скорее как подспорье или перепроверку результатов, чем как основной инструмент.

  • Почему классы, а не функциональные тесты - если речь о том, что на каждую функцию свой тест, то это относится с юнит-тестированию. Если вопрос в том, что один тест - один класс, то это далеко не всегда так - например, в разделе "Разделение api методов на .py файлы" я описываю случаи, когда в одном классе может быть много тестовых функций  - в одном  .py файле может быть, например, 2 класса один с позитивными и один негативными проверками, внутри которых будут описаны соответствующие тестовые функции. Разделение на классы в данном случае удобно для того, чтобы можно было быстрее и легче запустить скоупом все позитивные или все негативные проверки.

  • Если тест интеграции с Aws брать moto/boto или писать своё - в своей практике я использовала Boto3, так как нашей целью было интеграционное тестирование с реальными сервисами AWS. Но если у Вас такой необходимости нет, можно использовать и Moto, который эмулирует AWS API локально и позволяет вам запускать автотесты без использования реальных сервисов AWS. Если Ваш функционал совсем специфичный и его никак не покрыть возможностями существующих библиотек - то, можно подумать в сторону чего-то своего.

  • А где авто сборщик документации тестов а'ля swagger - документация по API методам (swagger) - как правило, реализуется на стороне разработки, в не в автотестах. Что касаемо документирования автотестов - тут скорее речь пойдёт про такие инструменты, как allure - а как настроить интеграцию с ним и как лучше писать тесты и аллюр аннотации, чтобы отчёты были максимально информативными - дело отдельной статьи))

Почему pytest вместо unittest или tavern- pytest предлагает более
простой, гибкий и мощный подход к автотестированию на Python, как по
мне, unittest лучше подходит для юнит-тестов, чем для автотестов.

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

А так пайтест имеем более простой синтаксис и много фич.

Исторически unittest сделали чтобы было, а pytest чтобы удобно. 10 лет назад это были день и ночь, сейчас unittest сократил отставание, но всё еще сильно позади.

Поиск и запуск тестов через pytest умеет находить и правильно запускать код написанный с помощь unittest.

Исторически unittest сделали чтобы было, а pytest чтобы удобно.

С этим я абсолютно согласна! Сама я пишу юнит-тесты с использованием pytest. Но среди разных проектов видела случаи, где разработчики использовали unittest. А вот в автотестировании я никогда не видела, чтобы кто-то использовал unittest, поэтому так и написала.

Спасибо, отличная статья!

Добрый вечер. Спасибо статью!

В python из коробки неудобно пользоваться словарём, особенно при большой вложенности. Используете ли вы библиотеки, например attrs, marshmallows и подобные ? Как вы валидируете ответ в response, например обязательные поля, тип и длину ?

Для валидации ответа в response мы не используем сторонние библиотеки (attrs, marshmallows и подобные) - мы используем свой подход. response мы представляем как объект — экземпляр класса. Мы парсим ответ (стандартными методами из коробки) в набор атрибутов и их значений. Под конкретный api метод мы создаём свой класс, в котором описываем множество обязательных полей, множество дополнительных полей и множества типов в виде:

fields_int = {'count', 'offset', 'limit'}   
fields_list = {'games', 'players'}

Далее проверяем на наличие обязательных и дополнительных полей, сравниваем множество атрибутов, пришедших в ответе с множеством, описанным к классе. Если какие атрибуты отсутствуют в ответе, то выводим ошибку с выводом разницы этих множеств. Далее следует проверка на типы - тут мы проверяем типы всех значений согласно объявленным в классе, например, значения атрибутов 'count', 'offset', 'limit' из примера выше мы проверяем на то, что они типа int. И третий метод-проверка - это проверка данных - тут мы проверяем и длину полученного значения, например, если есть лимит по длине значения, и при необходимости значение. Например, мы сделали запрос с определённым id пользователя и в ответе хотим проверить, что значение id равно переданному в запросе, по такие значения мы передаём в качестве переменной в метод проверки, например, assert_data(id). В случае наличия вложенных объектов, мы такие объекты тоже представляем в виде класса. Это удобно тем, что такие классы легко переиспользовать. Например, есть респонс-объект и информацией о подписке и там есть объект "Тариф" - мы его выделяем в отдельный класс (поля, типы, проверки значений) и когда к нам приходит респонс-объект "Информация о пользователе", в котором есть такой же объект "Тариф", то мы его заново не пишем, а используем уже описанный класс "Тариф". Возможно, при большом уровне вложенности данный подход не подойдёт, но в нашем случае подходит очень хорошо. Также мы сделали класс с общими проверками (на наличие полей и типов), от которого мы наследуемся в классах-респонсах, чтобы у них, как у наследников были эти методы и не приходилось бы каждый раз писать их заново.

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

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

Зарегистрируйтесь на Хабре, чтобы оставить комментарий