Make It Right! Максимум пользы, минимум проблем: рекомендации по написанию API автотестов на Python |
11.12.2023 00:00 |
Автор: Катерина Верхошинская (инженер по автотестированию в Газпром-Медиа Холдинг)
Меня зовут Катерина, я инженер по автотестированию в команде онлайн-кинотеатра PREMIER и сегодня я хотела бы поделиться с вами своим опытом в написании API автотестов на Python. Я работаю в сфере автотестирования уже довольно давно и на практике встречаю проекты из разных сфер деятельности (банкинг, ритейл, телекоммуникации, строительство, развлечения и др.) зачастую, работая над ними, я сталкивалась с одной общей проблемой - код автотестов был тяжелым в понимании и плохо масштабируемым. Приходилось его капитально рефакторить, а это совсем невесело;) В этой статье я хочу поделиться советами, как сделать ваш код более «чистым», легким в понимании и расширении. Мне всегда хочется думать, что тот, кто будет работать с моим кодом в будущем, будет думать обо мне и моём коде в положительном ключе, а не ругаться на него. Если вы разделяете мою философию, прошу под кат. Итак, приступим! Прежде чем начать писать сам автотест, очень важно изучить документацию по вашему проекту и сделать сценарии, по которым вы будете создавать автотесты. В большинстве случаев автотестировщики пишут автотесты по уже готовым сценариям, поэтому на данном пункте мы долго останавливаться не будем, а вот изучение документации перед написанием автотестов является неотъемлемой частью процесса разработки. Только с таким знанием мы сможем написать качественные и полнофункциональные автотесты, которые будут эффективно проверять работу нашего программного продукта. На какие вопросы нужно получить ответы, прочитав документацию по api методу:
Не стоит забывать о том, что документация изменчива, порой аналитики (и не только они) вносят туда правки, что-то меняется, что-то удаляется, что-то добавляется и всегда стоит держать руку на пульсе - следить за актуальной документацией и вовремя вносить правки в свои автотесты. Конечно, бывают случаи, когда документация очень скудная или её попросту нет, к сожалению, такое бывает, и я не раз с таким сталкивалась. В таких случаях стоит обратиться к “хранителю знаний”. Им может быть аналитик, разработчик или тестировщик, который уже сталкивался с этим методом до вас. Главное - найти этого человека и попросить поделится знаниями. Документация изучена, кейсы написаны - пришло время писать код! Проработка архитектуры проектаВ первую очередь стоит подумать об архитектуре проекта, конечно, только если вы пишете его с нуля, так как в противном случае - об этом уже позаботились ваши предшественники и вам остается только адаптироваться под уже существующую архитектуру и код стайл ;) Но все же если вы стали первопроходцем и пишете проект с нуля, то проработка архитектуры тестового фреймворка будет вашей стартовой точкой, и от того, как вы его спроектируете, зависит вся ваша последующая работа и тех, кто будет работать вместе с вами над этим проектом. Давайте рассмотрим несколько ключевых аспектов, которые помогут вам построить правильную архитектуру для написания автотестов API. Выбор языка программированияВыбор языка программирования является первым и одним из самых важных шагов в разработке тестового фреймворка. Рекомендуется выбрать язык, в котором у вас есть опыт разработки или который наиболее удобен для вашей команды. Наиболее популярными языками для разработки тестовых фреймворков являются Python, Java, Ruby и Type Script.
Структура проекта Важно определить правильную структуру проекта для удобства его использования и поддержки. Рекомендуется использовать модульный подход и разделить тесты, вспомогательные функции и конфигурацию на разные модули или пакеты. Это поможет вам легко находить и исправлять ошибки, а также добавлять новые тесты. Давайте рассмотрим два самых распространенных и удобных в использовании подхода: 1. Разделение api методов на .py файлыВ данной реализации мы под каждый API метод создаем отдельный .py файл и в нём пишем тесты только на этот метод. Данные файлы будут располагаться в папке с тестами, которая, в свою очередь, будет лежать в корне проекта. Внутри файла мы можем создавать тестовые классы, например, класс с позитивными проверками и класс с негативными проверками, а внутри этих классов уже прописывать тестовые функции, где каждая функция будет отображать один тест-кейс. Рассмотрим пример: Например, у нас есть POST метод Активации промокода Мы создаем .py файл и называем его Далее уже внутри этого файла создадим два класса: для позитивных кейсов и
для негативных кейсов Что же, основной каркас создан, давайте приступим к наполнению и обогащению нашего тестового фреймворка. Для этого посмотрим на наши тест-кейсы, давайте начнем с позитивных кейсов, потому что, как известно, если позитивный тест не проходит, то в негативном и смысла нет)) Тот самый ответ, который ждут от кандидатов на собеседованиях когда просят протестировать карандаш;)
Вот так, например, может выглядеть название позитивного кейса, когда нам нужно проверить успешную активацию промокода. О том, как именно стоит называть классы и тестовые функции мы поговорим чуть позже. В корне проекта будет располагаться ряд очень важных для проекта файлов: ЛогиПрежде всего, хотелось бы отметить такой важный пункт в автотестировании, как логирование. Если у вас не настроено логирование, вы никогда не узнаете, из-за чего ваше приложение упало и не сможете отследить, что привело к ошибке. Вы не сможете профилактически поглядывать в логи, чтобы следить за работоспособностью приложения и узнать состояние своей системы в момент времени N. Как правило, подключение логирования и его настройки производятся в файле с конфигурациями (в частности, conftest.py в pytest). А сами логи, результат работы логирования, хранятся в отдельном файле, например log_test.txt. При данной архитектуре проекта оба этих файла будут лежать в корне проекта. В языке Python основным инструментом для логирования является библиотека Подробно познакомится с этой библиотекой вы можете в официальной документации Также не стоит забывать и о наполнении логов, по умолчанию формат выглядит так: <УРОВЕНЬ>: <ИМЯ_ЛОГГЕРА>: <СООБЩЕНИЕ>. Но при желании вы можете расширить его дополнительной информацией, датой, названием файла с ошибкой, названием тестового метода, номером строки и так далее. Сделать это можно с помощью параметра Например, если вы зададите вот такой формат:
То вывод ошибки будет выглядеть так:
Не стоит впихивать в формат логов слишком много информации, стоит лишь указывать только ту информацию, которая действительно нужна вам и вашим коллегам. КонфигиКогда мы говорим о фреймворке по автотестированию с использованием pytest, есть несколько конфигурационных файлов, которые должны присутствовать для успешной работы.
Вот, собственно, основные файлы, которые должны присутствовать в фреймворке по автотестированию, использующем pytest. Разумеется, внутри этих файлов вы можете задать свои параметры и настройки, чтобы адаптировать фреймворк под свои потребности. Тестовые данныеДля тестовых данных лучше всего создать отдельную папку или отдельный файл, в котором мы будем их хранить и вызывать их непосредственно из самого теста. Как правило, папка с тестовыми данными(файлами) лежит в корне проекта. В данной папке могут храниться разные файлы с тестовыми данными .json или .csv. Чаще всего это .py файлы, в которых хранятся данные, используемые в тестах, например:
и уже непосредственно в самих тестах мы импортируем данный класс и обращаемся к нужному нам промокоду.
Также тестовые данные могут браться из БД. Также если реальная система работает с бд, то естественно, необходимо в автотестах проверить эту работу, чаще всего в этом случае делается копия боевой бд и заполняется тестовыми данными для тестирования. И наши автотесты будут брать, изменять и, если надо, удалять данные из этой тестовой бд. При работе с БД хорошей практикой считается использование ORM, например, SQLAlchemy. Файл с общими проверками (checkers.py)Более подробно о данных функциях-проверках я расскажу чуть позже Также в корне каталога расположится очень важный файл .gitlab-ci.yml с нашим пайплайном, но это уже другая история. 2. Разделение api методов на папки/директорииВ данной реализации под каждый API метод создается своя директория/папка и внутри этой папки хранятся все файлы, связанные конкретно с этим API. В этой папке будут лежать все файлы, которые относятся к данному методу. Например, все тестовые данные, которые мы будем использовать для тестирования данного метода, также тут могут храниться данные о базах данных, которые мы используем конкретно в этом методе, могут храниться какие-то конфиг-файлы. Ну и, конечно, самое главное – в данной папке будут храниться .py файлы, в которых будут написаны сами автотесты к данному методу. При данной архитектуре часто используется такой подход, что в каждом отдельном .py файле мы пишем ровно один тест. Выбор архитектуры зависит от многих факторов, и все их нужно учитывать при проектировании. Я привела примеры самых часто встречаемых архитектур тестовых фреймворков для API автотестов на Python. Для каждого проекта все настраивается индивидуально, под нужды команды. Написание автотестовПосле того, как мы проработали архитектуру, можно приступать непосредственно к написанию самих тестов: Нейминг
Комментарии
Ассерты
Это искусственный пример, но такого типа ассерты я встречала и в реальной жизни
Методы-ЧекерыЕсли вы пишете проверку, которая часто используется, например, проверка статус кода, то такие проверки лучше вынести в функции.
Тут стоит отметить что если есть возможность использовать значения по умолчанию - используйте, в данном случае используется status_code равный 200, так как он встречается в большинстве проверок. Это упростит и сократит код вызова функции.
Стоит избегать прямой проверки json Например:
Такой код опять же лучше заменить на метод или, если у вас есть четкая задача проверить именно полное совпадение json которой вы получили в ответе апишки с ожидаемым json, то стоит вынести его в тестовые данные. Принципы разработки ПОДавайте немного освежим в памяти базовые принципы по разработке ПО. Если вы никогда о них не слышали, то вы можете обнаружить, что некоторые из них вы применяете интуитивно. Принцип: Не придумывайте к задаче более сложного решения, чем ей требуется. Иногда самое разумное решение оказывается и самым простым. Одна из основных ошибок начинающих разработчиков - использовать что-то очень сложное там, где это совершенно не нужно, чтобы показать свою “компетенцию” - что они знают эту сложную технологию и хотят это всем доказать. Изучить технологию - это значит не только изучить синтаксис, но и понять, где и когда ее действительно нужно использовать. Принцип: Не стоит дублировать код Дублирование кода не только пустая трата времени и ресурсов, но и дополнительная работа по его исправлению. Вам придется поддерживать одну и ту же логику сразу в нескольких местах, причем если вы измените код в одном месте, его нужно будет изменить и в другом. В большинстве случаев дублирование кода происходит из-за незнания вашего проекта (уже написанного кода, которого может быть очень много). Прежде чем что-либо писать, внимательно изучите код проекта, и, если есть сомнения можно уточнить у более опытных коллег. Возможно, уже где-то реализована функция, которая дублирует ваш код. Повторное использование кода, самое разумное решение. Принцип: Пишите только нужный код, который точно будет использоваться Очень простой и очевидный способ, о котором многие новички почему-то забывают. Когда пишете код, обязательно убедитесь, что он действительно будет использоваться, а не висеть мёртвым грузом. Если вы всё-таки решились на написание такого кода, потому что на 100% уверены, что в ближайшее время он пригодится вам или кому-то из ваших коллег, то обязательно оставьте к такому коду комментарий с пометкой о том, что на данный момент он не используется, но будет для таких-то целей и укажите примерную дату, когда код станет используемым. Данный комментарий будет очень важен вашим коллегам, да и вам тоже, в частности, например, для того, чтобы его случайно не удалили за ненадобностью. Данный принцип часто используется при рефакторинге кода, когда мы рассматриваем весь код, классы, методы, и смотрим, используются ли данные классы, данные методы, нужны ли эти переменные или нет. И если мы видим, что код не используется и нигде не вызывается, то мы его просто удаляем. В случае же, если мы наталкиваемся на подобный неиспользуемый метод, но у него написан комментарий с пометкой о том, что скоро он действительно будет нужен, что его удалять не стоит, то, естественно, удалять его никто не станет, и он скоро сыграет свою роль в автотестах. Принцип Бритва Оккама - это философский принцип, который гласит, что из двух объяснений, объясняющих одно явление, необходимо выбирать наиболее простое и лаконичное. Применение этого принципа в автотестировании имеет несколько причин: Экономия времени и ресурсов: применение данного принципа позволяет сократить объем работы и сфокусироваться на наиболее значимых и существенных тестовых сценариях. Оптимальное использование ресурсов сохраняет время и средства, затрачиваемые на написание и поддержку автотестов. Увеличение читаемости и понятности автотестов: создание простых и четких автотестов позволяет легче и быстрее понять их назначение и реализацию. Это упрощает сопровождение автотестов и упрощает коммуникацию между членами команды. Снижение вероятности ошибок: сложные и запутанные автотесты могут стать источниками ошибок. Простые и прямолинейные автотесты более надежны, легче понять и проверить их выводы. Это позволяет предотвратить ошибки и улучшить качество автотестов. Адаптация к изменениям: использование Бритвы Оккама позволяет создавать автотесты, которые могут легко адаптироваться к изменениям в приложении. Простые автотесты менее чувствительны к изменениям, поэтому их проще поддерживать и обновлять. В целом, применение принципа Бритвы Оккама при написании автотестов помогает сделать их проще, более эффективными и надежными, что в конечном итоге повышает качество автотестов. Принцип: Избегайте преждевременной оптимизации Принцип Avoid Premature Optimization используется в программировании, включая написание автотестов, чтобы избегать оптимизации кода до тех пор, пока она фактически не станет необходимой. В контексте автотестов данный принцип означает, что в начале разработки автотестов необходимо фокусировать внимание на функциональности продукта и проверке корректности работы программного обеспечения. Это подразумевает создание тестовых сценариев, проверку основных функций и логики программы. Оптимизация автотестов, различные рефакторинги, включая улучшение скорости выполнения или уменьшение нагрузки на ресурсы, должна происходить только после достижения уверенности в корректной работе проверяемого продукта. Если заняться оптимизацией раньше, это может привести к затратам лишнего времени и ресурсов на улучшение кода, который впоследствии может быть изменен или даже удален. Кроме того, принцип Avoid Premature Optimization также может помочь в сохранении читаемости и понятности кода. Если сразу начать оптимизировать автотесты, то код может стать более сложным для понимания и поддержки, что усложнит работу вам и вашим коллегам. Использование принципа Avoid Premature Optimization позволяет сосредоточиться на проверке функциональности и корректности программного обеспечения, а оптимизацию оставить на более поздний этап разработки. Это помогает улучшить эффективность разработки и поддержки автотестов. Подведем итоги: В этой статье мы с вами рассмотрели различные способы, как сделать ваш код более «чистым», легким в понимании и расширении. В заключение хочу отметить, что написание автотестов - это непрерывный процесс обучения и совершенствования, поэтому экспериментируйте, изучайте, обменивайтесь опытом и всегда стремитесь к созданию более эффективных и продуктивных автотестов. Надеюсь, что эти советы помогут вам в достижении успеха в вашем тестировании! |