Как пишется автотест

Как начать писать автотесты на Java

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

Трудности начнут появляться по мере роста проекта. Увеличение числа автотестов заставит задуматься об оптимизации скорости их выполнения, организации кода, паттернах проектирования. Сложные кейсы и дальнейшее развитие тестового фреймворка уже потребуют уверенных знаний языка программирования и использования различных библиотек. Чем глубже будет проходить погружение тем с большим количеством технологий придется взаимодействовать, что одновременно и сложно и увлекательно.

Свои первые шаги в автотестах я делал в Яндексе, откуда затем проделал долгий путь до руководителя команды автоматизации тестирования во ВКонтакте, где на момент написания статьи вместе с коллегами развиваю тестовые фреймворки и инструменты для экосистемных проектов VK.

Меня периодически спрашивают «какими знаниями нужно обладать, чтобы начать писать автотесты на Java». В данной статье собрал список того, что считаю полезным со ссылками на материалы для изучения.

Определиться с языком программирования

В 2023 году Java всё ещё один из самых популярных языков программирования, в том числе для автоматизации тестирования. Но прежде чем погрузиться в мир Java, убедитесь, что именно она подходит вам и вашему проекту.

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

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

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

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

  • TIOBE – рейтинг основан на количестве инженеров работающих с языком, курсов и поисковых запросов из Google, Bing, Yahoo!, Wikipedia, Amazon, YouTube и Baidu.
  • PYPL (PopularitY of Programming Language) – индекс ориентируется на то, как часто в Google ищут учебные материалы по определенному языку.
  • StackOverflow – рейтинг на основе самого популярного форума программистов.
  • Octoverse – рейтинг крупнейшего сервиса для хостинга IT-проектов и совместной разработки.
  • IEEE – рейтинг института инженеров электротехники и электроники.

Вместе с Java в автоматизации тестирования уверенно лидируют Python, JavaScript и С#.

Научиться программировать

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

Ниже представлены ссылки на курсы и книги, которые будут полезны как для изучения Java так и программирования в целом.

Курсы по Java

  • Официальный онлайн учебник по Java от Oracle
  • JavaRush. Один из лучших онлайн-курсов по программированию на Java
  • CodeGym – клон JavaRush на английском языке
  • Java Basics (и другие курсы по Java) от Epam
  • Интерактивный курс по Java от Sololearn
  • Курс Java for Beginners от Hyperskill и JetBrains
  • JavaBegin – fullstack обучение Java/Kotlin для новичков и профессионалов
  • Вопросы для собеседования на Java Developer

Книги по Java

  • Изучаем Java. Бэйтс Берт, Сьерра Кэти
  • Java. Руководство для начинающих. Герберт Шилдт
  • Java для чайников. Барри Бёрд
  • Java. Библиотека профессионала, Кей С. Хорстманн
  • Java. Методы программирования. Романчик Валерий, Блинов Игорь
  • Effective Java. Джошуа Блох
  • Философия Java. Брюс Эккель

Алгоритмы, паттерны и рефакторинг

  • Гарвардский курс «CS50. Основы программирования»
  • leetcode.com – онлайн сервис, где можно практиковаться в решении задач по программированию
  • Грокаем алгоритмы. Иллюстрированное пособие для программистов и любопытствующих
  • Head First. Паттерны проектирования. Эрик Фримен, Берт Бейтс, Кэти Сьерра, Элизабет Робсон
  • Чистый код: создание, анализ и рефакторинг. Роберт Мартин
  • Рефакторинг: улучшение проекта существующего кода. Мартин Фаулер
  • Код. Тайный язык информатики. Чарльз Петцольд
  • Алгоритмы на Java. Роберт Сэджвик, Кэвин Уэйн
  • Книга Погружение в паттерны проектирования, курс Погружение в Рефакторинг и примеры паттернов на GitHub от Александра Швеца, автора сайта Рефакторинг.Гуру. К сожалению сайт заблокирован в России, но доступен под VPN.
  • Статьи на Хабре Пожалуй, лучшая архитектура для UI тестов и Паттерны проектирования в автоматизации тестирования

Познать среду разработки

Писать код можно хоть в блокноте, но лучше использовать IDE (Integrated Development Environment) – интегрированную среду разработки.

Кроме текстового редактора и подсветки синтаксиса, IDE включает в себя инструменты автодополнения команд (autocomplete), предупреждения ошибок, рефакторинга, горячих клавиш (shortcut) и поиска. Встроены компилятор, средства автоматизации сборки, отладчик, терминал, система управления версиями.

IntelliJ IDEA

Несколько лет назад Eclipse и NetBeans довольно часто встречались в качестве рекомендуемых IDE для написания кода на Java. Сейчас их полностью вытеснила IntelliJ IDEA от JetBrains. Бесплатная Community Edition версия работает с Java и Android, которая покрывает потребности для написания автотестов.

В неумелых руках продвинутый инструмент пользы не принесёт. Чтобы использовать IntelliJ IDEA максимально эффективно, изучите её возможности, посмотрите курсы, и важно – выучите шоткаты!

  • Бесплатный курс по IntelliJ IDEA от Хайнца Кабуца
  • Официальное руководство и туториалы по IntelliJ IDEA
  • Канал IntelliJ IDEA от JetBrains на YouTube со множеством полезных гайдов
  • Несколько полезных роликов с Heisenbug про работу в IntelliJ IDEA от Юрия Артамонова: раз, два, три
  • Крутой плагин для изучения шоткатов
  • IntelliJ IDEA Course на YouTube
  • Создание проекта с нуля в IntelliJ IDE
  • IntelliJ IDEA. Профессиональное программирование на Java – книжка аж 2005 года, часть информации устарело, тем не менее пользу извлечь можно, и это единственная книга из известных мне на русском языке.

VS Code

Ещё одна популярная IDE Visual Studio Code так же предоставляет возможности для работы с Java. Если привычнее использовать её, рекомендую изучить официальный java туториал: Getting Started with Java in VS Code и Testing Java with Visual Studio Code.

Прокачать GIT

Работа с кодом, тем более в команде предполагает совместную работу с ним, поэтому умение работать с Git, а вместе с ним GitHub и GitLab – очевидный скилл не только для разработчика, но и любого айтишника, в том числе тестировщика.

Хорошая новость в том, что и IntelliJ IDEA и Visual Studio Code, как и большинство IDE умеют работать с Git через графический интерфейс. Однако, понимание того, что происходит «под капотом», позволит избежать возможных ошибок.

Материалы для изучения Git

Ниже несколько ресурсов для прокачки.

  • Pro Git book – самый популярный учебник по Git
  • Git How To – интерактивный курс
  • Git: наглядная справка – справочник по Git в картинках
  • Git: курс от JavaScript.ru на YouTube – аккуратный, необходимый, слегка «продвинутый»
  • Онлайн-курс «Введение в Git» от Хекслет
  • Learn Git Branching – интерактивный сервис для изучения Git.

Топ 10 команд Git

В повседневной работе с Git используется не так много команд.

Например, команда из примера ниже клонирует репозиторий проекта в текущую папку на компьютере.

git clone https://github.com/адрес-вашего-репозитория

Следующая команда переключится на master – главную ветку проекта.

git checkout master

Команда ниже подтянет из репозитория свежие изменения.

git pull origin master && git fetch

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

git checkout -b имя-ветки

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

git checkout имя-ветки

Следующая команда добавит все созданные и изменённые файлы в новый коммит.

git commit -a -m имя-коммита

Добавить все созданные и изменённые файлы к отслеживанию Git в текущей ветке, без создания коммита.

git add .

Добавить текщие изменения к текущему, ранее созданному коммиту.

git commit --amend

И последняя команда отправит вашу ветку с текущими коммитами в удалённый репозиторий.

git push --set-upstream origin название-удаленной-ветки

Если обнаружили ошибку, что-то поправили в локальной ветке и нужно по новой сделать пуш следом за отправленным, используйте ключ -f.

git push --set-upstream origin название-удаленной-ветки -f

Разобраться со стеком технологий

Итак, вы умеете программировать (хотя бы немного), как ниндзя применяете шоткаты в IntelliJ IDEA и можете запустить программу на выполнение, а ещё без особых трудностей пушите свой код в удаленный репозиторий и знаете как разрешить конфликты в Git. Если нет – ничего страшного, этому ещё предстоит научиться, но можно двигаться дальше.

Сборщики проектов Gradle и Maven

Современная программа состоит из множества файлов и подключенных библиотек. Если вы уже знакомы с Java то знаете, что прежде чем запустить программу на исполнение, сначала её нужно скомпилировать, превратив в байт код или как говорят «собрать». Ручная сборка проектов на Java – трудоёмкий процесс, чтобы его упростить и автоматизировать, существуют так называемые сборщики проектов.

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

Кроме того, программы редко пишутся с нуля и чаще всего используют сторонние наработки подключаемые в виде пакетов (библиотек) – зависимостей, которые могут хранится локально или располагаться в публичных репозиториях (как у npm в JS или Composer в PHP). Сборщики в том числе умеют управлять этими зависимостями, по-простому – подключать их к проекту. Для этого нужно лишь указать зависимость в конфигурационном файле.

Поиск пакетов для Maven и Gradle от JetBrains

Самые популярные сборщики для Java – Gradle и Maven. В ближайшее время постараюсь сделать небольшую статью по ним. А пока стоит запомнить, что:

  • Функционал Gradle и Maven схож, при выборе сборщика для проекта руководствуйтесь тем что уже используется командой.
  • Gradle популярнее Maven. Однако существует огромное количество проектов на Maven, и популярность не всегда играет решающую роль.
  • Конифг сборки Gradle на Groovy (файл build.gradle), короче XML, используемого в Maven (файл pom.xml).
  • У Gradle нет собственного репозитория, зависимости он загружает из репозитория Maven.
  • Gradle работает быстрее.

Полезные ресурсы по Gradle:

  • Официальный сайт Gradle
  • Документация Gradle
  • Онлайн события и тренинги по Gradle
  • Поиск зависимостей для Gradle

Полезные ресурсы по Maven:

  • Официальный сайт Maven
  • Maven репозиторий

Тестовые фреймворки JUnit и TestNG

Тестовые фреймворки нужны для того, чтобы уметь отделять код автотестов от кода программы (которого может и не быть если проект содержит только тесты), размечать, группировать в сьюты и запускать автотетсы.

Два самых популярных тестовых фреймворка для Java – JUnit и TestNG. Оба сильно схожи по функциональности. Подробное сравнение фреймворков и как подключить их к проекту можно почитать в моей статье JUnit vs TestNG.

JUnit сильно популярнее TestNG, однако как и в случае с Gradle / Maven популярность не всегда играет решающую роль, исходите из своих потребностей и того, что использует команда.

На своем основном проекте во ВКонтакте я использую связку TestNG / Gradle (так исторически сложилось и прекрасно работает), но для новых проектов чаще выбираю стек JUnit / Gradle, если не знаете что использовать, рекомендую попробовать последнее.

  • Официальный сайт JUnit 5
  • Официальный сайт TestNG

Selenium для автотестов в браузерах

Когда упоминают Selenium, часто подразумевают ним инструмент для автоматизации UI тестов выполняемых в браузере. Однако Selenium это целое семейство продуктов:

  • Selenium WebDriver – библиотека для управления браузерами, основной продукт, разрабатываемый в рамках проекта.
  • Selenium Server – сервер для управления браузером с удалённой машины по сети.
  • Selenium Grid – ПО для объединения нескольких Selenium-серверов в кластер.
  • Selenium RC – устаревшая библиотека для управления браузерами.
  • Selenium IDE – плагин для Chrome и Firefoх для записи и последующего воспроизведения действий пользователя в браузере. В контексте автоматизации тестирования на Java полностью бесполезен. Ради интереса можно «потыкать», но не более.

В контексте автоматизации тестирования интерес представляет Selenium WebDriver и в некоторой степени Selenium Server и Grid, но последние два чаще заменяют альтернативными инструментами.

Для управления Selenium WebDriver из Java, используется библиотека selenium-java. Ниже приведен пример её подключения для Gradle.

implementation('org.seleniumhq.selenium:selenium-java') {
  version {
    strictly seleniumVersion
  }
}

Как это работает:

  • библиотека selenium-java позволяет обращаться из Java кода к Selenium WebDriver;
  • WebDriver должен быть скачан на машину, с которой будет происходить запуск тестов;
  • путь к WebDriver указывается в проекте с автотестами при инициализации драйвера в коде;
  • для каждого браузера и даже каждой версии браузера нужна соответствующая версия WebDriver. Логика выбора версии драйвера для тестов реализуется в коде самостоятельно или через сторонние библиотеки, например WebDriverManager (ссылка на Maven Repository);
  • на машине (локально или на сервере) на которой будут выполняться тесты должен быть установлен браузер той же версии, что и WebDriver.
  • инженер по автоматизации пишет автотесты используя команды selenium-java, а «под капотом» общение selenium-java и WebDriver осуществляются по REST-протоколу;
  • если тесты будут гоняться удалённо, потребуется Selenium Server.

Полезные ресурсы по Selenium:

  • Официальный сайт проекта Selenium
  • Онлайн учебники по Selenium Webdriver от kreisfahrer и COMAQA
  • Много полезного материала с конференции Selenium Camp
  • WebDriverManager (ссылка на Maven Repository) – библиотека упрощающая управление веб-драйвером (загрузка, настройка, обслуживание)
  • Курс Алексея Баранцева Selenium WebDriver: полное руководство
  • Полезный ролик на YouTube от Simple Automation по работе с Selenium Webdriver
  • Статья по Selenium от BrowserStack
  • Подготовка к собеседованию по Selenium – 30 вопросов

Selenide – прокачанный Selenium

Selenide – фреймворк, надстройка над Selenium WebDriver, но более простая и удобная в использовании.

Чтобы оценить всю мощь и прелесть Selenide, попробуйте написать десяток тестов на Selenium, а затем повторите тоже самое на Selenide.

Вот тут вместе с примерами собраны основные преимущества Selenide против Selenium, рекомендую ознакомиться, но если кратко:

  • инициализация браузера 1 строкой кода вместо 5;
  • не нужно выполнять закрытие браузера, Selenide сделает это самостоятельно;
  • простые конструкции для поиска элементов;
  • простые ассерты;
  • умные ожидания – если элемент не отобразился на странице, потому что еще не загрузился, Selenide подождёт 4 секунды (по-умолчанию);
  • поиск элемента по тексту;
  • создание скриншотов одной командой;
  • и много других «плюшек».

Полезные ресурсы по Selenide:

  • Быстрый старт по Selenide (как подключить к проекту и написать первый тест)
  • Selenide wiki
  • Как написать UI тест за 10 минут на Selenide
  • Эффективные UI-тесты на Selenide – статья с обзором возможностей Selenide от его создателя Андрея Солнцева
  • Примеры использования Selenide на GitHub
  • Подборка сниппетов демонстрирующих функционал Selenide

Selenoid – прокачанный Selenium Server

Если Selenide – это Selenium «на стероидах», то аналогичное можно сказать про Selenoid представляющегося лучшей альтернативой в отношении Selenium Server.

Selenium Server сложен в установке и поддержке. Все компоненты (Java, браузеры, бинарники WebDriver-ов, Selenium Server) необходимо устанавливать и конфигурировать вручную, что скорее всего вызовет затруднения если вы не продвинутый системный администратор или DevOps. Решения на Selenium Server часто не всегда стабильны. Зависшие браузеры, а часто и сервер приходится перезапускать.

В противовес Selenium Server установка Selenoid выполняется в несколько команд. Есть готовые образы для облачных серверов, в том числе для Yandex Cloud. Его отличает простой понятный интерфейс и простота в обслуживании. Зависшие браузеры автоматически перезапускаются. Имеется поддержка очередей и записи видео прохождения тестов.

Selenoid запускает браузеры изолированно в Docker-контейнерах, и это не дань моде, а полезная фича – если потребуется новый браузер, просто скачивается и подключается новый контейнер.

Если вы уже используете Selenium Server, но хотите перейти на Selenoid, кроме адреса сервера в существующем проекте ничего не придется менять.

Полезные ресурсы по Selenoid:

  • Официальный сайт Selenoid
  • Документация по Selenoid
  • Selenoid на GitHub

Так же рекомендую посмотреть доклад Ивана Крутого, одного из создателей Selenoid и видео с Heisenbug Павла Сенина.

Тестирование API: REST Assured и Retrofit

Для API автотестов не нужны ни Selenium, ни Selenide, ни Selenoid. Чтобы отправлять запросы и получать ответы используя REST понадобятся другие инструменты: REST Assured или Retrofit. Однако кроме API тестов они могут быть полезны и при тестировании UI, например если необходимо сконфигурировать сущность участвующую в тесте, тестируемый сервис и/или проверить результат теста, когда по API это сделать проще чем через UI.

Пример простого автотеста с использованием REST Assured.

Отчеты с Allure Report

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

В TestNG функционал генерации отчетов работает «из коробки». JUnit не генерирует отчет, но сохраняет результат прогона автотестов, который можно привести к удобочитаемому с помощью плагинов. Однако есть инструмент, который превосходит по функционалу любое другое решение для построения отчётов – это Allure Report.

Функционал:

  • Группирует результаты веб и API-тестов, десктопных, мобильных в одном отчете.
  • Удобный интерфейс.
  • Тесты отображаются с подробным сценарием выполнения, включая. Если у теста есть вложения (логи, скриншоты, видео) Allure прилинкует их к тесту.
  • Гибкий фильтр, группировка, поиск.
  • Аналитика запуска тестов.
  • Поддержка не только Java, но и других языков программирования.
  • Интеграции с CI/CD системами.

Подробнее можно ознакомиться в докладе Артёма Ерошенко создателя Allure или почитать в статье на Хабре.

Полезные ресурсы по Allure Report:

  • Официальный сайт Allure Report
  • Как подключить к Java проекту
  • Документация Allure Report
  • Allure Report на GitHub

Continuous Integration

Настраивать CI прерогатива специалистов DevOps и тема для отдельной статьи. Однако, и автоматизатору данный скилл и понимание процессов несомненно полезны, особенно, если DevOps на проекте отсутствует.

Если не углубляться в подробности, то для тестирования важно уметь запускать автотесты при поставке новых фич в тестинг, релиз или продакшн и получать отчёт о результатах их прохождения. Указанное является лишь небольшой частью процесса непрерывной интеграции.

Самыми популярными CI/CD системами являются Jenkins, TeamCity, GitHub Actions, GitLab CI.

Полезные ресурсы по Jenkins:

  • Официальный сайт Jenkins
  • Мини руководство по Jenkins от Reg.ru
  • CI/CD на примере Jenkins. Автоматизация запуска тестов
  • Jenkins Pipeline. Что это и как использовать в тестировании
  • Jenkins 2. Приступаем к работе. Брент Ластер

Полезные ресурсы по TeamCity:

  • Официальный сайт TeamCity
  • Руководство по CI/CD в TeamCity
  • Пошаговые руководства TeamCity

Полезные ресурсы по GitHub Actions:

  • GitHub Actions
  • Автоматизируем все с Github Actions

Полезные ресурсы по GitLab CI:

  • GitLab CI/CD
  • GitLab CI для тестировщика (вебинар на YouTube)

Прочие полезные инструменты и библиотеки

Lombok – избавляет от необходимости написания шаблонного кода для геттеров, сеттеров, toString() и прочих, улучшая удобств и читаемость кода.

Gson – библиотека сериализации / десериализации для преобразования объектов Java в JSON и обратно.

Log4j – библиотека логирования и SLF4J – обёртка для различных библиотек логирования.

Сопутствующие технологии

Инженеру по автоматизированному тестированию недостаточно знаний одной лишь Java. В зависимости от тестируемого приложения или сервиса, придётся столкнуться со множеством других технологий.

Чтобы найти элемент на странице – нужно уметь строить локаторы, чтобы выполнить скрипт или поменять из кода значения в LocalStorage браузера – придется познакомиться с JavaScript, захотите обратиться к базе данных – пригодится SQL, понадобится определить действительно ли пользователь ввёл в поле адрес электронной почты добро пожаловать в мир регулярных выражений, а тестирование API подразумевает хорошее знание компьютерных сетей.

CSS и XPath локаторы

Автотесты для web-приложений постоянно взаимодействуют с web-элементами на странице. Нужно уметь строить их, используя локаторы.

Локатор (или селектор) – это выражение, которое идентифицирует элемент или группу элементов в DOM-дереве. Наиболее распространёнными являются CSS и XPath локаторы.

CSS локаторы включают в себя набор атрибутов web-элемента, в XPath – это путь до элемента в DOM-дереве.

Обычно на проекте используют один из видов локаторов, комбинировать их без понятной причины не рекомендуется. Выбор CSS или XPath зависит от личных предпочтений и договорённостей в команде.

  • Как писать CSS/XPath локаторы в Selenium WebDriver
  • Про типы локаторов и CSS, XPath, jQuery
  • Шпаргалка по локаторам
  • Мануал по XPath
  • И немного практических примеров в статье Эффективные UI-тесты на Selenide

HTML, CSS и JavaScript

  • HTML Academy: интерактивные онлай-курсы по HTML, CSS и JavaScript
  • HTMLBook.RU – онлайн самоучитель и справочник посвященный HTML и CSS
  • Онлайн курс по Веб-программированию от университета ИТМО
  • W3Schools – интерактивный учебник по web технологиям
  • Sololearn – интерактивный учебник по HTML, CSS, JS, JQuery, PHP, SQL, Java и другим языкам
  • Самый популярный онлайн учебник по JavaScript на русском языке
  • Справочник по JavaScript на Mozilla Developer Network
  • Учебник: Выразительный Javascript

Регулярные выражения

  • Регулярные выражения (Regexp) от Хекслет
  • Регулярные выражения. Джеффри Фридл
  • Регулярные выражения. Сборник рецептов. Ян Гойвертс, Стивен Левитан

Работа в консоли

  • Основы командной строки. Курс на Хекслет
  • Введение в Linux

Компьютерные сети

  • Онлайн курс Основы DevOps от Epam
  • Учебный курс Андрея Созыкина «Компьютерные сети» (на YouTube)
  • Компьютерные сети. Принципы, технологии, протоколы Виктор Олифер, Наталья Олифер

Для любителей курсов

  • Автоматизатор тестирования на Java от Яндекс Практикум
  • Школа инженеров по автоматизации тестирования QA.Guru
  • Инженер по тестированию: с нуля до middle от Нетологии
  • Тестировщик на Java
  • Тренинги Алексея Баранцева

Что еще

Научиться методу слепой печати

Советы новичкам:

  • Нажимайте клавиши только правильными пальцами и всегда возвращайте пальцы в исходную позицию «ФЫВА – ОЛДЖ», это основа метода слепого набора.
  • Не смотрите на клавиатуру.
  • Уделите внимание развитию безымянных пальцев и мизинцев обеих рук – их моторика хуже остальных, но они не меньше остальных пальцев участвуют в наборе текста.
  • На первых порах фокусируйтесь на качестве, а не на скорости, и постепенно доводите до автоматизма.

Сервисы для тренировки метода слепой печати:

  • Клавогонки
  • СОЛО на клавиатуре (только для WIndows)
  • Klava.org
  • Keybr

Подтянуть английский

  • Английский от Яндекс Практикума
  • Puzzle English
  • Puzzle Movies – английский по фильмам и сериалам
  • Duolingo
  • Lingualeo

Чек-лист автоматизатора

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

Если желание писать автотесты не угасло, надеюсь, что минимум – появилось понимание стека технологий для автоматизации тестирования, максимум – сложился некий «roadmap», из которого понятно, над чем стоит стоит подумать и какие скилы нужно подтянуть.

Чек-лист инженера по автоматизации тестирования на Java выглядит примерно так:

  • определился с языком программирования, в идеале – это язык, на котором пишут разработчики в команде, если это Java – есть понимание почему именно она;
  • может рассказать про ООП, его принципы (абстракция, инкапсуляция, наследование, полиморфизм) и объяснить что такое класс, интерфейс, объект;
  • знает чем различаются JRE, JVM и JDK;
  • знает, что такое переменные, каких типов они бывают, сколько места в памяти занимают и какие существуют модификаторы доступа;
  • умеет работать с условиями, циклами, массивами, коллекциями;
  • понимает, что такое PageObject, представляет, что такое паттерны и может применять некоторые из них;
  • чтобы запустить программу не использует мышь или тач-бар и знает ещё c десяток шоткатов;
  • может клонировать проект, отвести от него ветку, внести свои изменения, сделать коммит, запушить обратно в общий репозиторий и не боится конфликтов и ребейзов;
  • не путается в названиях Gradle, Maven, JUnit, TestNG, понимает их назначение и может использовать в проекте;
  • знает что такое Selenium, Selenide, Selenoid и использует две из трёх технологий;
  • без шпаргалок составляет CSS и XPath локаторы;
  • умеет использовать REST Assured или Retrofit для API-тестов;
  • любит или не любит Lombok;
  • каждый день заглядывает в Allure Report;
  • уже настроил несколько пайплайнов в Jenkins или поигрался Selenoid в GitHub Actions;
  • … большой молодец раз осилил так много технологий.

На этом всё. Но вы можете поддержать проект. Даже небольшая сумма поможет нам писать больше полезных статей.

Если статья помогла или понравилась, пожалуйста поделитесь ей в соцсетях.

25.06.2020 00:00

Автор: Ольга Назина

Сделать это довольно легко, потому что в Postman-е есть
документация с примерами. Более того, эти примеры можно найти в самом инструменте на вкладке «Tests», они называются «Snippets».

Вот только если вы не знакомы с языками программирования, получившийся тест будет из разряда «Оу, магия!». А что, если вы хотите подкорректировать тест? Поменять под себя? Какую часть можно трогать, а какую оставить как есть?

В этом видео я возьму пример из сниппетов Postman-а, и подробно объясню, что означает каждая его часть. Теперь редактировать будет не страшно! 

А если вы хотите узнать больше — подписывайтесь на мой youtube-канал и приходите на курс “Автоматизация тестов для REST API при помощи Postman”, где вы сможете научиться писать автотесты в Postman, используя возможности языка JavaScript.

На первый запуск 9 июля скидка 30% по промокоду «first_start» (для получения скидки нужно ввести промокод в поле Код купона).

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

Продолжаем погружаться в работу тестировщика, он же — QA, quality assurance engineer. Его задача — проверить код на наличие ошибок и работу программы в разных условиях. 

Мы уже писали о том, что ещё делают тестировщики и какие инструменты для этого используют:

  • Кто такой инженер по тестированию и стоит ли на него учиться
  • Зарплата 113 тысяч за то, чтобы ломать программы
  • Тестируем и исправляем калькулятор на JavaScript
  • Словарь тестировщика: автотесты, юнит-тесты и другие важные слова
  • Какой софт нужен, чтобы стать тестировщиком

Сегодня мы попробуем написать автотесты — чаще всего именно этим занимаются тестировщики на работе.

Что такое автотесты

Автотесты — это когда одна программа проверяет работу другой программы. Работает это примерно так:

  1. У нас есть код программы с нужными функциями.
  2. Мы пишем новую программу, которая вызывает наши функции и смотрит на результат.
  3. Если результат совпадает с тем, что должно быть, — тест считается пройденным.
  4. Если результат не совпадает — тест не пройден и нужно разбираться.

Чтобы всё было наглядно, покажем работу автотестов на реальном коде.

Исходная программа

Допустим, мы пишем интерактивную текстовую игру — в ней всё оформляется текстом, и развитие игры зависит от ответов пользователя. Мы сделали отдельный модуль, который делает четыре вещи:

  • получает имя игрока;
  • принудительно делает в имени большую букву (вдруг кто-то случайно ввёл  с маленькой);
  • добавляет к нему приветствие;
  • сформированную строку отправляет как результат работы функции.
# Собираем приветствие
def hello(name):
    # делаем первую букву имени большой
    out = name.title()
    # формируем приветствие
    out = 'Привет, ' + out + '.'
    # возвращаем его как результат работы функции
    return out

Эта функция хранится в файле hello_function.py — так мы разбиваем программу на модули, каждый из которых делает что-то своё. 

Напишем начало основной программы, которая запрашивает имя, формирует приветствие и добавляет к нему стартовую фразу:

# импортируем функцию из другого файла
from hello_function import hello
# объясняем, что нужно сделать пользователю
print("Введите имя, чтобы начать игру")

# спрашиваем имя
name = input("Как вас зовут: ")
# обрабатываем имя и формируем приветствие
result = hello(name)
# добавляем вторую строку
print(result + " nДобро пожаловать в «Код»!")

Сохраним это в новом файле start.py и запустим его:

Делаем простые автотесты на Python

Вроде работает, но хорошо бы проверить, а всегда ли приветствие будет формироваться правильно? Можно сделать вручную, а можно написать автотест.

Пишем автотест

Первое, что нам нужно сделать, — подключить стандартный модуль для автотестов unittest. Есть модули покруче, но для наших проектов стандартного хватит с запасом. Также получаем доступ к функции hello() из файла hello_function.py — работу именно этой функции мы будем проверять автотестом.

# подключаем модуль для автотестов
import unittest
# импортируем функцию из другого файла
from hello_function import hello

А теперь самое важное: нам нужно объявить класс и функцию, внутри которой и будет находиться наш тест. Причём название функции должно начинаться с test_, чтобы она выполнялась автоматически.

Внутри функции делаем такое:

  • формируем данные, которые мы отправляем в тестируемую функцию;
  • прописываем ожидаемый результат.

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

Для запуска тестов добавляем в конец кода стандартный вызов. Читайте комментарии, чтобы лучше вникнуть в код:

# подключаем модуль для автотестов
import unittest
# импортируем функцию из другого файла
from hello_function import hello

# объявляем класс с тестом
class HelloTestCase(unittest.TestCase):
    # функция, которая проверит, как формируется приветствие
   def test_hello(self):
        # отправляем тестовую строку в функцию
        result = hello("миша")
        # задаём ожидаемый результат
        self.assertEqual(result, "Привет, Миша.")

# запускаем тестирование
if __name__ == '__main__':
    unittest.main() 

После запуска мы увидим такое. Ответ «OK» означает, что наш тест сработал и завершился без ошибок:

Делаем простые автотесты на Python

Тест пройден за ноль секунд

Ещё такие тесты позволяют найти ошибки в самом коде. Допустим, разработчик забыл добавить принудительный перевод большой буквы в имени, и тогда тест не пройдёт. Если получится, система даже подсветит, что именно не совпало в результате, — в нашем случае это первая буква имени.

Делаем простые автотесты на Python

Тест не пройден, а автотестер даже указал в чём

Что дальше

Мы написали самый простой тест и всего с одним условием. При этом мы не проверили тестами работу основной программы — в реальном проекте это тоже нужно было бы сделать. Чтобы попрактиковаться, мы сделаем тесты для одного из наших старых проектов на Python. Заодно проверим, нет ли там каких ошибок, которые мы не заметили.

Вёрстка:

Кирилл Климентьев

На связи команда Айтигро. В статье подробно расскажем, что такое автотесты, когда и как их нужно и не нужно использовать, а также на конкретном примере разберем опыт внедрения автотестов в проекте «Наигру».

Автотесты в веб-сервисы Наигру: сценарии

Что такое автотесты простым языком?

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

В интернете встретили хорошую аналогию: представьте что мост — это программа (или в нашем случае веб-сервис). По мосту запускаем полностью нагруженный товарный состав (виртуальный трафик). Когда поезд едет по мосту, на котором установлены датчики, мы получаем информацию о трещинах, деформации балок, разрушении железнодорожного полотна. Это есть end-to-end тестирование (подробнее описано ниже). А вот если добавить, что после каждого изменения моста (добавление балки, изменение геометрии опор и т.д.) поезд запускается автоматически, а датчики, улавливая ошибку, не пропускают его дальше – то это уже автоматическое end-to-end тестирование.

Простое тестирование – это когда после изменения конструкции моста мы запускаем поезд вручную и смотрим, оцениваем, выдержит ли мост поезд или нет (и ставим под мост тестировщиков и разработчиков, ха-ха).

С определениями разобрались. Поехали дальше.

Что и как можно автоматически тестировать?

Автоматически можно тестировать программный код или пользовательский интерфейс. В статье мы будем говорить про автотесты через пользовательский интерфейс.

Если говорить совсем точно, статья будет про автоматическое end-to-end (E2E, сквозное) тестирование, имитирующее пользовательскую среду и поэтапно моделирующие действия пользователей.

Автоматическое end-to-end (E2E) тестирование — это процесс автоматического тестирования с подробной эмуляцией действий пользователя: кликаньем мышки, переходами по страницам, заполнения форм и так далее. Цель E2E тестирования — удостовериться, что программа работает именно так, как задумано для конечного пользователя.

E2E тестирования обычно проводится в самом конце перед «выкаткой» изменений или доработок на рабочие версии продуктов. Поэтому ошибки, возникающие при некачественном E2E тестировании, могут быть очень дорогими.

Пример. Мы «выкатываем» приложение с потенциалом 10 000 регистраций в месяц. Предположим, мы не заметили, что после изменения одной из функций пользователи не видят модальное окно об успешной регистрации и это снижает общую конверсию на 5%. Стоимость одной регистрации составляет 15 долларов. За первый месяц мы потеряем 7 500 долларов.

Типы E2E тестирования: черный и белый ящик

Метод черного ящика — метод тестирования, при котором проверяется только интерфейс. Ошибки в логике не отслеживаются.

Метод белого ящика — метод тестирования, при котором проверяется сопоставление работы программы с эталоном.

Мы в проекте использовали метод белого ящика и проверяем правильность работы не только блоков интерфейса, но и логики.

Как мы пришли к автотестам в проекте Наигру

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

Когда в проект добавилось множество механик, из-за которых структура проекта стала разрастаться, на проекте стали возникать ошибки там, где мы их совсем не ожидали. Возникла классическая проблема: дорабатывая дополнительный функционал начал ломаться базовый.

Например, перестала работать кнопка «Записаться на игру» после доработки механизма перехода игроков из резерва в основной состав. Или при создании регулярных игр возникали баги в обычных разовых играх – например, при записи на игру не показывалось модальное окно об успешном действии и пользователь не мог понять, записан ли он.

Наигру: Ошибка «Не показывается модальное окно»

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

Ручное тестирование

Сначала проблему решали введением регулярного классического ручного регрессионного тестирования — проверяли, чтобы ранее созданный и проверенный функционал продолжал корректно работать после добавления нового.

Регрессионное тестирование делится на 3 уровня: проверка нового блока, проверка ранее добавленных блоков, а также проверка связанных и не связанных сторонних блоков после добавления или изменения блока. В среднем одно такое тестирование занимало два рабочих дня.

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

Подготовка к автоматическому тестированию

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

  • Регистрация/авторизация пользователей

  • Создание и редактирование игры
  • Запись на игру
  • Отписка игрока от тренировки
  • Запись в резерв, переход в основной состав

Сформировали алгоритмы поведения пользователей

Например, проверка регистрации: сайт открывается → выбор чекбокса города Москва → нажатие «Сохранить» → нажатие на «Войти или создать аккаунт» → проверка ошибки неправильно заполненного телефона → ввод сгенерированного номера → нажатие «Войти» → проверка наличия авторизации после регистрации и выход из профиля.

Созданные алгоритмы поведения пользователей использовали в тестах критически важных функций сайта: авторизация, создание игры, приглашение на игру, запись на тренировку, отписку от тренировки, механизм перевода игрока из резерва в основной состав и т.д.

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

Наигру: проверка алгоритма действий организатора
Наигру: проверка алгоритма действий игрока

Что получили в итоге?

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

То есть новые функции или изменения в принципе не могут быть запущены на рабочем сайте без прохождения автотестов. Это последний рубеж защиты от программных ошибок и экономических потерь бизнеса.

Отчет об автоматическом тестировании (пайплайн)

Email с отчетом по итогу автотестирования

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

Было/стало

Ручное тестирование:

  • Тестировали только функционал, который дорабатываем – пропускали непрогнозируемые ошибки базового функционала
  • Узнавали о проблемах по факту – тратили много времени на поиск причины и на ее устранение

Автотесты:

  • Без полной проверки базового функционала на рабочий сайт не попадает ни одна доработка
  • Узнаем о проблеме заблаговременно и затрачиваем меньше ресурсов на устранение

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

Про инструментарий (Внимание! Начинается техническая часть)

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

Селениум:

  • Не user-friendly
  • Сложнее отследить, на каком моменте тест провален – отсутствует система репортов

Сайпрес:

  • Удобен для написания тестов и отладки – продуманный интерфейс
  • Наглядно показано (информация и скриншот), на каком моменте и по какой причине тест провален

У каждого инструмента есть свои нюансы

Например, Cypress, на котором остановились мы, не сохраняет Cookie и LocalStorage между тестами. В нашем случае это влияет на сохранение данных о пользователе между тестами (данные об авторизации), чтобы алгоритм работал так, будто действия создает один и тот же пользователей. Для устранения этой проблемы мы подобрали плагин (cypress-localstorage-commands), который сохраняет необходимые данные между тестами, а также настраивали файл конфигурации, чтобы сохранялись Cookie.

Файл конфигурации: сохранение Cookie

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

Экспериментальные функции сессий: сохранение Cookie

Отдельные элементы кода

Капча (CAPTCHA) тоже может мешать запуску автотестов – в рамках тестов настроили авторизацию по POST-GET запросу к API, минуя интерфейс авторизации.

Авторизация по POST-GET запросу к API

Разновидность сайта

Есть и свои нюансы автотестов для разных типов сайтов. Наигру реализован как Single Page Application – для такого рода сайтов “скриптовые” ошибки, которые не являются критичными для работы сервиса, мешают работе теста. Их приходилось отключать, чтобы предотвращать провалы теста, так как инструмент не пропускал алгоритм дальше.

Скриптовая ошибка

Структура кода

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

В проекте Наигру подобной проблемой стало расположение селекторов в структуре HTML-древа. Как итог – невозможно настроить тест таким образом, чтобы он понимал, какому конкретному организатору принадлежит игра. Этот момент необходимо учитывать при построении алгоритма тестирования

Необходимые навыки для создания автотестов

С автоматизаций тестирования вполне справится опытный тестировщик.

Для этого специалисту необходимо:

  • базовые навыки программирования и знание JavaScript (преимущественно автотесты пишутся именно на нем)
  • знание Node.js – помогут при установке плагинов и настройке связей между спецификациями
  • понимание особенностей построения архитектуры HTML-древа и работы селекторов
  • знание Git – для более эффективного взаимодействия с командой разработки, поможет создавать “коммиты” и загружать их в проект

Чтобы специалисту за довольно короткое время освоить автотестирование понадобится документация выбранного инструмента автоматизации и парочка роликов на youtube. Наш тестировщик вдохновлялся каналом Глеба Бахмутова.

Со сложными для понимания вопросами можно обратиться к коллеге-программисту уровня мидл и выше.

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

Реализация автоматического тестирования – гармоничный путь развития тестировщика. Таким образом специалист все больше наращивает знания программирования и уходит от ручного тестирования в сторону более сложного и перспективного. С таким бэкграундом дальше он сможет двигаться к квалификации разработчика.

Золотое соотношение в видах тестирований

В отрасли применяют разные соотношения между ручными и автотестами. Например, в Google автотесты занимают около 10% от всего вида тестирования, а остальные тесты выполняются специалистами вручную.

Главное правило звучит так: автотестов должно быть существенно меньше, чем обычных – иначе это приведет к существенному удорожанию поддержки проекта.

Мы не советуем покрывать автотестами более 10-15% функционала.

Заключение

С точки зрения реализации – автоматическое тестирование можно сделать под любой проект.

Преимущества автотестов:

  • Быстро находят критичные ошибки
  • Нет человеческого фактора – непредвзятые
  • Накапливают сценарии для регресс-тестирования

Слабые места:

  • Требуют постоянной доработки
  • Могут возникнуть сложности при разработке теста, если изначально на проекте не предполагалось использовать автоматическую проверку
  • Польза от автотестов не всегда окупает затраты на их подготовку (если базовый функционал проекта постоянно изменяется, то и автотесты придется менять каждый раз вместе с ним – в таком случае это будет занимать больше времени и сил, чем ручное тестирование)

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

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

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

Пожалуйста, поставьте статье upvote (стрелочка вверх), мы старались :)

Привет! Меня зовут Артём Комаренко, я работаю на позиции QA Lead в команде PaaS в СберМаркете. Хочу поделиться историей, как мы придумывали способ быстро убедиться, что очередные изменения в скриптах деплоя не разломают процесс выкатки во всей компании. 

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

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

<a name=»why»>Зачем всё это?</a>

В Сбермаркете мы разрабатываем PaaS, и одной из важных частей нашей платформы является CI/CD pipeline. То есть наши пользователи-разработчики получают «из коробки» готовый pipeline, в котором уже есть различные задачи по запуску тестов, линтеров и прочих ништяков, а также задачи по выкатке приложения на тестовые стенды и созданию релиза для выкатки на прод.

И вот однажды ко мне пришел лид команды DevOps с запросом «Хочу автотесты!»

<a name=»plan»>План действий</a>

Мы определили, что для PaaS важно убедиться, что разработчик, который первый раз воспользовался нашими инструментами, сможет без проблем выкатить свежесозданный сервис. А для DevOps инженеров было важно знать, что после внесения изменений в скрипты всё ещё можно спокойно деплоить новую версию приложения поверх существующей. 

Таким образом определился базовый набор сценариев: 

  • деплой нового сервиса;

  • деплой существующего сервиса.

Сценарии отличаются началом, где мы получаем сервис, и списком проверок. И в общем виде выглядят так:

  1. Создать новый (или клонировать существующий) сервис локально

  2. Внести и запушить изменения в удаленный репозиторий

  3. Найти пайплайн МРа

  4. Выполнить джобу деплоя

  5. Проверить, что джоба завершилась успешно

  6. Проверить, что в неймспейсе появились нужные поды/контейнеры

  7. Остальные проверки

Три кита, на которых держится автотест:

  1. Для работы с локальным репозиторием нам нужен git, соответственно была выбрана библиотека GitPython.

  2. Работать с gitlab было решено по API, для этого как раз подходит библиотека python-gitlab.

  3. С k8s так же решено работать по API, и здесь так же есть библиотека kubernetes.

С вводными определились, можно приступать к написанию теста.

<a name=»script»>Скриптуем в лоб</a>

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

Основные действия я вынес в методы хелперов:

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

  • хелпер для работы с Kubernetes. 

Для красивых проверок я использовал библиотеку assertpy.

if name == '__main__':
    repo = RepositoryHelper(remote_host)
    kubectl = Kubernetes(service_name)
    repo.clone(service_name)
    os.chdir(service_path)
    repo.make_local_changes()
    repo.push_local_branch(branch_name)
    repo.create_mr(branch_name)
    repo.find_pipeline(mr)
    repo.run_job('deploy', pipeline)
    assert_that(job).has_status('success')
    kubernetes.find_pod('app')
    assert_that(app_pod).has_status('running')

Скрипт сработал. И тут же я столкнулся с первой трудностью – следующий прогон падал, потому что состояние тестового репозитория изменилось. Нужно за собой прибраться: дописываем в конце нашего скрипта инструкции по откату изменений в репозитории, закрытию МРа, удалению ветки, чистке неймспейса.

if name == '__main__':
    ...
    repo.checkout_local_branch(recovery)
    repo.push_local_branch(recovery, force=True)
    repo.close_mr(mr)
    repo.remove_remote_branch(branch_name)
    kubectl.remove_namespace(namespace_name)

Теперь можно запускать прогоны один за другим, все работает. Но как только что-то пошло не так, тест упал — чистка не произошла. Пришло время использовать привычный тестовый фреймворк – pytest.

<a name=»test»>Тест здорового человека</a>

Основным вызовом при переходе к pytest стало понять что и как перенести в фикстуры, чтобы в тесте осталась только логика самого теста. В фикстуры переехал функционал по подготовке локальной среды к тесту, инициализации хелперов, клонированию репозитория, и самое важное — чистка по завершению.

Как итог, наш скрипт преобразился в стандартный тест:

class TestDeploy:
  def test_deploy_new_service(repo, kubernetes, branch_name):
    repo.local.make_changes()
    repo.local.push(branch_name)
    repo.remote.create_mr(branch_name)
    repo.remote.find_pipeline(mr)
    repo.remote.run_job('deploy', pipeline)
    assert_that(job).has_status('success')
    kubernetes.find_pod('app')
    assert_that(app_pod).has_status('running')

За счет очистки в финализаторах фикстур, тест стал проходить даже если в середине произойдет сбой. А также теперь можно создавать и запускать любое количество тестов, а не по одному, как было раньше.

<a name=»cicd»>Перемещаемся в пайплайн</a>

При запуске локально тесты работают. Но нам нужно переместить их в пайплайны. Сразу перейду к списку того, что потребовалось тюнить:

  • Git. На локальной машине для идентификации используется ssh-ключ, а в пайплайне – нет. Если для работы с удаленным репозиторием вместо ssh использовать http-протокол, то после вызова команды потребуется ввести логин и пароль. Но у git’а есть возможность указать значение store в настройку  credential.helper, и тогда можно сохранить креды в формате https://{user}:{token}@{host} в файл .git-credentials

  • Учетная запись. На локальной машине используется моя собственная учетка, логин и пароль знаю только я, доступы есть везде, куда нужно. Но транслировать свои креды на удаленную машину – плохая идея. Мы создали сервисную учетку с доступами только до требуемых проектов.

<a name=»manydevs»>Раз разработчик, два разработчик…</a>

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

Нужно создать больше тестовых репозиториев. Но как тест узнает, какой репозиторий использовать? В рантайме эту информацию не удержать, случайный выбор не даёт гарантий. 

Я решил создать отдельный сервис, который заберет на себя эту работу.

<a name=»box»>Коробка с болванчиками</a>

Я использовал наш PaaS и написал небольшой сервис на Golang. Список тестовых репозиториев и их статус хранятся в Postgres.

Сервис предоставляет три gRPC-ручки:

  • LockRepo — блокирует самый давно неиспользуемый сервис и отдает его данные

  • UnlockRepo — разблокирует указанный сервис

  • GetReposList — возвращает список всех сервисов

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

Блокировку и разблокировку тестового сервиса я вынес в фикстуру:

@pytest.fixture()
def project_info():
    repo = DummiesBox.lock_repo()
    yield repo
    DummiesBox.unlock_repo(repo.id)

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

<a name=»future»>Развитие</a>

На двух простых тестах мы не остановились.

Уже сделано:

  1. Мы расширили скоуп проверок в каждом тесте, проверяем как вместе с сервисом разворачиваются его ресурсы: postgres, redis и т.п.

  2. У нас есть несколько вариантов деплоя: стабильный стейдж, отдельным подом, отдельный стейдж. Добавили тесты для каждого.

  3. PaaS поддерживает несколько языков, для каждого свой деплой. Добавили тесты для основных языков.

  4. Наработки автотестов деплоя позволили реализовать автотесты рейтлимитера, в которых мы точечно проверяем как он отработал в зависимости от настроек.

Сейчас основные направления для дальнейшего развития:

  1. Автотесты для деплоя на прод

  2.  Проверка оставшихся языков, для которых есть наш деплой

  3. Отстрел сервиса в процессе деплоя

<a name=»problems»>Проблемы</a>

Разумеется, трудности встречались регулярно и до конца никогда не исчезнут. Инфраструктура может сбоить, что приводит к падению теста. Вот примеры некоторых проблем:

  • сетевая проблема в облаке (недоступно, долго отвечает, 500-тит);

  • кончились ноды и kubernetes не может поднять под;

  • заняты все раннеры в CI/CD;

  • спам тестов из-за частых коммитов;

  • неявное изменение бизнес логики, когда тест в целом проходит, но иногда падает, а на что смотреть — непонятно.

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

<a name=»overall»>Резюме или А что по цифрам?</a>

Основной набор состоит из 5 e2e-тестов. При нормальных условиях тест проходит за ~15 минут. Бегают они параллельно.

Тестовый набор запускается минимум 1 раз на МР и в среднем 10-15 раз в день, в зависимости от нагрузки инженерной команды. В месяц выходит порядка 250 запусков тестового набора.

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

Если вы хотите попробовать такие тесты у себя, то чтобы превратить их в рабочий код нужно:

  1. Реализовать методы взаимодействия с репозиторием и kubernetes. Обычно для этого достаточно взять готовую функции из официальных библиотек и добавить логи.

  2. Добавить ожидания для пайплайнов и задач. Я использую библиотеку waiting для этого.

  3. Добавить проверки для всех своих ресурсов. В общем случае я проверяю:

    • статус  задач в пайплайне

    • наличие и статус подов в kubernetes

    • статус контейнеров внутри подов в kubernetes

  4. Реализовать способ поставки тестовых репозиториев. У меня это отдельный сервис, но возможно вы найдете другой способ.

Буду рад, если наши наработки вам пригодятся. Если вы писали автотесты для деплоя как-то по-другому, то интересно будет услышать, в чём мы разошлись!

Tech-команда СберМаркета завела соцсети с новостями и анонсами. Если хочешь узнать, что под капотом высоконагруженного e-commerce, следи за нами в Telegram и на  YouTube. А также слушай подкаст «Для tech и этих» от наших it-менеджеров.

Содержание

  1. Что такое автотесты
  2. Документация
  3. Инструменты
  4. Паттерны проектирования
  5. Что можно автоматизировать
  6. Советы для разработки автотестов
  7. Общий код стоит выносить
  8. Писать переиспользуемый код
  9. Тесты должны быть удобными
  10. Тесты должны быть простыми
  11. Разделение на модули
  12. Интеграции
  13. Главное кратко

Когда проект становится очень большим, а ручные тесты отнимают все больше времени и средств, требуется автоматизация тестирования. Тестировщик Даниил Шатухин рассказывает, как выстроить архитектуру автотестов на Java, чтобы потом не пришлось все срочно переделывать и оптимизировать.

Что такое автотесты

Под автоматизацией тестирования понимают написание скриптов, которые выполняют тесты за мануальных тестировщиков. Такие системы состоят из сложных сценариев проверки функциональности проектов, сбора статистики, фиксирования багов и генерации отчетности. Может показаться, что если однажды автоматизировать базу тестов, то можно навсегда забыть про долгий процесс тестирования каждого билда. Но автотесты надо постоянно актуализировать и поддерживать. Это первое, о чем стоит задуматься до внедрения автотестов в проект.

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

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

Документация

Подумайте, что именно предстоит автоматизировать.

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

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

  • рутинные тесты, которые занимают много времени, часто запускаются и требуют постоянного воспроизведения. Например, в проекте есть анкета для обратной связи с большим количеством полей и входных данных. Ручное заполнение может занимать 5–10 минут, а запуск автоматизированного теста — несколько секунд. Автоматизация позволит освободить время на более приоритетные и интересные задачи;
  • места с заведомо большим количеством багов. На каждом проекте они разные, но к ним, например, может относиться и часто обновляемый код.

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

Инструменты

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

При выборе фреймворка стоит обращать внимание на наличие подробной документации, его популярность и актуальность. Если последний раз фреймворк обновляли несколько лет назад, то его выбирать не стоит. Также необходимо хранить историю версий кода автотестов, генерировать подробные отчеты и выполнять интеграцию CI/CD.

Обычно стек инструментов и технологий для автоматизации на Java выглядит так:

  • Selenide — популярный фреймворк для автоматизации тестирования веба на базе Selenium WebDriver;
  • Allure Testops — инструмент для простого создания подробных отчетов. Поддерживает скриншоты, скринкасты и снапшоты состояния страниц во время выполнения теста. Все это позволяет не только увидеть наличие ошибок, но и посмотреть на сами ошибки визуально;

Отчеты в Allure Testops

Интерфейс запущенных тестов в Allure Testops

  • JUnit — инструмент для модульного тестирования ПО на Java;
  • Rest Assured — библиотека для работы с REST-службами и тестирования API;
  • Jenkins — открытая система для непрерывной интеграции ПО;

Непрерывная интеграция Jenkins

Пример запущенных и отработанных тестов в Jenkins

  • Git — распределенная система управления версиями. Можно использовать любой удобный сервис, к примеру GitHub, GitLab или Bitbucket. При желании можно поднять собственный git-сервер.

Наверняка во время работы над автотестами появится необходимость в сторонних библиотеках, которые упрощают и ускоряют разработку. Со временем в проект можно установить несколько десятков библиотек, которые не используются в полном объеме. Все это замедляет сборку, так как каждая библиотека порождает зависимости. К примеру, популярная библиотека построена на вспомогательных инструментах от других разработчиков, и при ее установке в нашем проекте оказывается вся коллекция этих инструментов. Все это замедляет время сборки тестов и нагружает систему.

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

Паттерны проектирования

Автоматизация тестирования — уже сложившаяся сфера со своими правилами и подходами. Для упрощения разработки существует набор паттернов проектирования:

  • Для структурирования кода существует понятие Page Object. Принцип заключается в объединении элементов страниц в свойства класса. Важно, что для каждой страницы создается ровно один класс, который содержит элементы в качестве свойств. В одном модуле мы храним локаторы, а в другом — взаимодействуем с ними. Это помогает повторно использовать локаторы и давать им понятные названия.
  • Для запуска одних и тех же тестов с разными данными обычно используется подход Data Providers. Буквально представьте, что в вашем проекте есть отдельный модуль, поставляющий данные для тестов. Вам не надо самостоятельно генерировать данные, а достаточно просто вызвать ранее написанный модуль. Это упростит работу и поможет сэкономить время, ведь можно будет просто обратиться к «поставщику».
  • Также следует использовать декораторы и дополнительные методы фреймворков, к которым можно отнести аннотации JUnit. Например, с помощью аннотации Issue, Story, CsvSource и Feature можно указать версию тестируемого приложения, кратко описать тестовый сценарии, добавить ссылку на тест в трекинговую систему или указать список тестовых данных.

Что можно автоматизировать

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

Мобильные приложения и «железо» обычно тестируют отдельные QA-команды. Связано это с тем, что в тестировании приложений есть свои особенности и сценарии, которые практически не встречаются в веб-приложениях, а для тестирования «железа» необходимы специальные навыки. Фронтенд- и бэкенд-тестировщики обычно работают вместе и часто общаются с разработчиками этих систем.

Из всех тест-кейсов надо выбрать наиболее приоритетные. Если проект находится на стадии разработки, то надо начинать с тестирования бэкенда. Дело в том, что клиентская часть еще может поменяться, и тогда QA-команде придется переписывать тесты. А вот серверную часть вряд ли переделают перед самым запуском. Но и это не все, эти тестовые сценарии тоже надо рассортировать по приоритету.

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

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

Советы для разработки автотестов

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

Общий код стоит выносить

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

Писать переиспользуемый код

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

Тесты должны быть удобными

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

Тесты должны быть простыми

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

Разделение на модули

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

Интеграции

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

Главное кратко

  • Автоматизация тестирования — сложный процесс, требующий времени на внедрение и ресурсов на поддержание. Нельзя написать код один раз и оставить его без присмотра.
  • Автотесты принесут пользу только при грамотном подходе и выборе инструментов. Иначе они просто заберут силы и время.
  • Не надо автоматизировать всё подряд. Важно в первую очередь заняться теми частями проекта, которые имеют наибольшую значимость.
  • Тесты должны быть «человечными». Зеленая галочка в терминале после прогона не даст никакой полезной информации менеджерам и другим участникам команды. Поэтому следует уделить время генерации подробной и понятной отчетности, из которой каждый сможет получить необходимые для себя данные.
  • Код автотестов должен быть простым и понятным. Сложные конструкции и низкоуровневые вставки сделают только хуже.
  • Использование большого количества сторонних библиотек чаще несет больше вреда, чем пользы. Библиотеки тянут за собой зависимости, которые замедляют сборку. Некоторые вещи уже могут быть реализованы в стандартной библиотеке Java.

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

Но, как я уже упоминал в одной из статей, есть у него один пробел по сравнению с pytest — это отсутствие адекватной параметризации тестов. Справедливости ради, у Robot Framework есть надстройка, которая позволяет генерировать тесты на основе внешней таблицы. Но это не совсем то, что нам подходит.

После прошлой статьи многие спрашивали меня, как именно делается параметрическая генерация автотестов. В этой статье отвечу на вопрос.


Проект-иллюстрация

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

  Горох может иметь цвет (Color) и тип (Kind):

from colors import Color
from kinds import Kind
 

class Peas:
 
    color: Color
    kind: Kind
 
    def __init__(self, color: Color, kind: Kind):
        self.color = color
        self.kind = kind
 
    def __str__(self):
        return f"{self.color.name().capitalize()} {self.kind.name()} горошек."

Не будем усложнять: класс переопределяет метод __str__() и выводит полную информацию о свойствах этого сорта гороха. Для иллюстрации этого будет вполне достаточно.

Добавим базовый класс «Цвет» (Color) и унаследуем от него основные — Зеленый и Желтый:

class Color:
    color_name: str = "неизвестный цвет"
 
    def name(self) -> str:
        return self.color_name
 
 
class Green(Color):
    color_name = "зелёный"
 
 
class Yellow(Color):
    color_name = "жёлтый"

Теперь опишем базовый тип и унаследуем от него основные — Гладкий и Сморщенный (он же — Мозговой):

class Kind:
    kind_name: str = "неизвестная форма"
 
    def name(self) -> str:
        return self.kind_name
 
 
class Smooth(Kind):
    kind_name = "гладкий"
 
 
class Brain(Kind):
    kind_name = "мозговой"

Базовый тест

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

from colors import Green, Yellow
from kinds import Smooth, Brain
from peas import Peas
 

def test_green_smooth_peas():
    peas = Peas(Green(), Smooth())
    assert str(peas) == "Зелёный гладкий горошек."
 
 
def test_yellow_smooth_peas():
    peas = Peas(Yellow(), Smooth())
    assert str(peas) == "Жёлтый гладкий горошек."
 
 
def test_green_brain_peas():
    peas = Peas(Green(), Brain())
    assert str(peas) == "Зелёный мозговой горошек."
 
 
def test_yellow_brain_peas():
    peas = Peas(Yellow(), Brain())
    assert str(peas) == "Жёлтый мозговой горошек."

Это все замечательно работает, но я живу по принципу: «Если пишешь что-то дважды — значит, делаешь что-то не так!»

Параметризация тестов

Вынесем цвет и тип в параметры и напишем генерацию параметров через умножение (product()) списков:

from itertools import product
from typing import Tuple
 
from pytest import mark
 
from colors import Color, Yellow, Green
from kinds import Kind, Smooth, Brain
from peas import Peas
 
colors = [(Yellow(), "Жёлтый"), (Green(), "Зелёный")]
kind = [(Smooth(), "гладкий"), (Brain(), "мозговой")]
peas_word = "горошек"
 
sets = list(product(colors, kind))
 

@mark.parametrize("color_info,kind_info", sets)
def test_peas_str(color_info: Tuple[Color, str], kind_info: Tuple[Kind, str]):
    color, color_str = color_info
    kind, kind_str = kind_info
    peas = Peas(color, kind)
    assert str(peas) == f"{color_str} {kind_str} {peas_word}."

Теперь мы ничего не дублируем и имеем те же четыре теста.

 И в случае расширения функциональности (например, добавим новый — черный — цвет) нам не придется писать еще много кода. Напоминаю, что мы очень сильно упрощаем реальные тесты реальных продуктов.

Добавим черный цвет:

class Black(Color):
    color_name = "чёрный"

Теперь, чтобы тестов стало шесть, достаточно просто изменить список цветов в модуле тестов:

colors = [(Yellow(), "Жёлтый"), (Green(), "Зелёный"), (Black(), "Чёрный")]

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

Названия кейсов

Возможно, первое, что бросилось в глаза при запуске таких тестов, — это не совсем приятное описание кейсов:

Не самое удобное описание кейсов.

Не самое удобное описание кейсов.

Для исправления этого недоразумения нужно для каждого кейса сгенерировать название и передать в параметризацию. Очень жаль, но русские буквы оно не любит, а наш метод возвращает только их. Поэтому будем обращаться к названию тестируемого класса:

test_names = [
  f"{params[0][0].__class__.__qualname__} - {params[1][0].__class__.__qualname__}" 
  for params in sets
]

Теперь пропишем их имена в параметризацию:

@mark.parametrize("color_info,kind_info", sets, ids=test_names)

Совсем другое дело:

Теперь всё понятно.

Теперь всё понятно.

Расширенная генерация тестов

Лучшее — враг хорошего. Именно поэтому я страдаю от применения кортежей в качестве костылей. Кстати, это хороший повод рассказать о расширенной отдельным методом генерации тестов.

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

 Есть в pytest зарезервированное название метода — pytest_generate_tests. Этот метод будет вызываться для каждого теста в модуле:

def pytest_generate_tests(metafunc):
    args = []
    names = []
    for color_info, kind_info in product(colors, kinds):
        color, color_str = color_info
        kind, kind_str = kind_info
        args.append([color, color_str, kind, kind_str])
        names.append(f"{color.__class__.__qualname__} - {kind.__class__.__qualname__}")
    metafunc.parametrize("color,color_str,kind,kind_str", args, ids=names)
 
 
def test_peas_str(color: Color, color_str: str, kind: Kind, kind_str: str):
    peas = Peas(color, kind)
    assert str(peas) == f"{color_str} {kind_str} {peas_word}."

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

Когда расширенная генерация тестов необходима

Иногда разработчики, уставшие от тонны issue, которые валятся как из рога изобилия в процессе написания автотестов, просят меня отключить какие-то кейсы. Чтобы не валить билд, зная заранее, что некоторые проблемы пока существуют.

Откровенно говоря, это не самая правильная практика и не стоит перенимать такой опыт. Но это хороший повод показать, почему иногда подход «расширенной» генерации незаменим и не может быть выполнен обычным @mark.parametrize.

Если вы еще не сталкивались с тем, как сделать тест при падении серым вместо красного (это не валит билд, но отмечает проблему), то это очень просто. Нужно использовать @mark.xfail. При необходимости в качестве параметра reason можно передать идентификатор issue в вашем баг-трекере.

Итак, представим, что по ТЗ у нас должен быть еще фиолетовый цвет горошка. Но разработчики с ним что-то напортачили, и тесты по нему падают. Разработчики просят нас сделать так, чтобы тесты фиолетового цвета проходили, но не валили билд.

Если тесты упали -- билда не будет.

Если тесты упали — билда не будет.

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

params = [color, color_str, kind, kind_str]
args.append(
  params if not isinstance(color, Purple) else pytest.param(*params, marks=pytest.mark.xfail(
    reason="Not implemented yet."))
)

Весь метод будет выглядеть так:

def pytest_generate_tests(metafunc):
    args = []
    names = []
    for color_info, kind_info in product(colors, kinds):
        color, color_str = color_info
        kind, kind_str = kind_info
        params = [color, color_str, kind, kind_str]
        args.append(params if not isinstance(color, Purple) else pytest.param(*params, marks=pytest.mark.xfail(
            reason="Not implemented yet.")))
        names.append(f"{color.__class__.__qualname__} - {kind.__class__.__qualname__}")
    metafunc.parametrize("color,color_str,kind,kind_str", args, ids=names)

А результаты выполнения будут отмечены серым и не будут валить билд в CI:

Теперь в отчёте видно какие тесты падают, но на сборку это не повлияет.

Теперь в отчёте видно какие тесты падают, но на сборку это не повлияет.

Когда еще необходима расширенная генерация тестов

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

Привычный всем подход @mark.parametrize("param", self.params) не будет работать, потому что на момент параметризации он еще не знает, что такое self. И тут мы снова возвращаемся к pytest_generate_tests, добавив его в класс:

def pytest_generate_tests(self, metafunc):
    metafunc.parametrize("param", self.params)

Такой подход уже будет работать.

И еще небольшая хитрость. Если вам нужно выполнить генерацию только для конкретного теста или по-разному организовать генерацию для разных тестов внутри pytest_generate_tests (напомню, он выполняется для каждого метода, начинающегося с test_ отдельно), можно обратиться к его параметру metafunc и получить свойство metafunc.function.__name__ — там и будет имя теста. Например,

class TestExample:
    params: List[str] = [“I”, “like”, “python”]
 
    def pytest_generate_tests(self, metafunc):
        if metafunc.function.__name__ == “test_for_generate”:
            metafunc.parametrize("param", self.params)
    
    def test_for_generate(self, param: str):
        print(param)
 
    def test_not_for_generate(self, param: str):
        print(param)

…сгенерирует тесты для test_for_generate, но не сделает этого для test_not_for_generate.

Заключение

На моем текущем проекте есть сервис, который сочетает разные фильтры и сегменты, каждый из которых является отдельным классом, и использование pair-wise может дать размытый результат. Вследствие чего не будет понятно, в каком именно классе ошибка. Генерируя тесты, я могу добиться 100%-го покрытия тестами, которые будут давать четкие результаты.

Всего в этом сервисе на данный момент почти 11 тысяч тестов. Не представляю, как бы я это все покрывал без такой генерации.

 Всем зеленых тестов и стопроцентного покрытия!

Понравилась статья? Поделить с друзьями:
  • Как пишется автосохранение
  • Как пишется автослесарь вместе или раздельно
  • Как пишется автосервис слитно или раздельно
  • Как пишется автосервис вместе или раздельно
  • Как пишется авторы