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

Стек: Java, Selenide, Allure, Jenkins
Давайте не будем говорить о конкретном проекте, а представим ситуацию в вакууме? Рано или поздно каждый тестировщик сталкивается с довольно масштабным продуктом, который с каждым релизом все сложнее и сложнее тестировать вручную. И вот, вы уже не помните, когда в последний раз проводили регрессию, потому что времени на нее все нет; не знаете, когда же это время появится; и все больше и больше ощущаете гнетущую ауру багов, скрывающихся в том функционале, до которого никак не доходят руки. Смоук занимает сначала 4 часа, потом день, потом полтора и вы, наконец, решаетесь: «Тут нужны автотесты!».

Представим, что и команда, и заказчик прыгают от радости и выделяют вам целые 20 часов неделю на протяжении некоторого отрезка времени, за которые вы можете заняться «этими самыми автотестами». Но что же делать дальше?
Документация
Начнем с того, что нам нужно понять, а что же все-таки автоматизировать? Итак, нам понадобятся следующие вещи:
    1
    Тест-план

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

    Здесь расположился один из самых ответственных этапов автоматизированного тестирования. Нам нужно не просто выбрать кейсы и начать писать код, следует определить основную цель наших автотестов.
    В ситуации, описанной в самом начале статьи, мы хотим сократить время на ручное тестирование, а значит, по максимуму автоматизировать Смоук (ведь он проводится часто). Также, это позволит нам покрыть часть регрессии и найти время на ее полное проведение.
      Еще из полезных вещей, на которые можно опираться при выборе Тест-кейсов, следует упомянуть:

      • функционал, с максимальным багрейтом (где находится большое количество багов);

      • функционал, требующий рутинного тестирования с большим количеством данных.
      Стоит помнить, что есть вещи, которые в принципе сложно автоматизировать: проверки открытия файла в сторонней программе, проверка содержимого изображения, проверки, связанные с ajax скриптами.
      Выбор инструментов
      Очевидно, что выбор инструментов автоматизации будет зависеть от стека технологий, на котором написан сам проект. Давайте представим, что мы хотим автоматизировать UI. На Java. Какой язык программирования мы выберем для тестов? Java! :)

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

      Не забываем, что помимо самых тестов, нам нужны читабельные отчеты и интеграция в CI/CD.

      Вот, что мы выбрали для нашего «проекта в вакууме»:
      1
      Selenide

      Фреймворк для автоматизированного тестирования веб-приложений на основе Selenium WebDriver.
      2
      JUnit

      Библиотека для модульного тестирования программного обеспечения на языке Java.
      3
      Allure

      Фреймворк от Яндекса для создания простых и понятных отчетов автотестов.
      4
      Jenkins

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

      Открываем IntelliJ IDEA, используем Maven (фреймворк для автоматизации сборки проектов на основе описания их структуры в файлах на языке POM, вот тут getting started) и начинаем настройку.

      Добавляем в проект Selenide (getting started), Junit (getting started), Allure (getting started) прописывая dependencies в pom.xml:
      Замечательно. Теперь пишем простенький тест, чтобы убедиться, что у нас все правильно настроено:
      Запускаем кнопочкой «play» справа, или через mvn test в терминале и смотрим, как у нас открывается по умолчанию Google Chrome и логинится. Начало положено, но не все так просто.
      Паттерны
      Автоматизация тестирования имеет собственный набор задач, так что существует и набор полезных паттернов проектирования для этой области.


      Первая группа паттернов

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

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

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

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

      • ParameterizedTest (позволяет запускать один и тот же тест с разными значениями, а еще красиво пишет в отчете название теста и параметры)

      • CsvSource (данные, с которыми запускается тест, можно указать вручную)

      • Feature, Story, Issue (наводят красивости в отчетах, описывая функциональность, юзер-стори и добавляя ссылку на тест-кейс в трекинговой системе)
      Четвертая группа паттернов

      И последняя на сегодня группа паттернов - это паттерны взаимодействия с бизнесом. Из них мы используем Steps.

      Когда мы используем логический сценарий, он состоит из шагов, а когда реализуем его в коде, зачастую шаги теряются: появляются вызовы каких-то технических деталей, подготовка данных и тд. Поэтому в виде отдельных методов мы описываем те или иные шаги, пряча внутри все «запутывающие» технические штуки:
        Интеграция с Jenkins
        Вот мы построили какую-никакую архитектуру, пишем красивые и понятные тесты, они у нас копятся и в один прекрасный момент мы понимаем, что сидим уже полчаса, ждем пока они прогонятся, а чай уже закончился. Да еще и разработчик тыкает в ребро и просит прогнать автотесты на новой сборке. Как быть? Интегрироваться в CI/CD!
        Допустим, наш большой проект в вакууме уже имеет развернутый Jenkins на серваке и его настройкой нам заниматься не надо (но если надо, есть getting started). В таком случаем нам предстоит настроить джобу для наших тестов, чтобы была возможность самостоятельно в любой момент тригеррить прогон. И бонусом не помешало бы встроить автотесты в пайплайн общей сборки, в нашем случае frontend, чтобы при каждом обновлении окружения тесты прогонялись автоматически.

        Создаем новую джобу, указываем, откуда брать код и не забываем про параметры: нам важно иметь возможность вручную указать ветку (по умолчанию собирается мастер), окружение, на котором хотим прогонять тесты, браузер (тут используем список поддерживаемых браузеров из Тест-плана) и размер окна браузера:
        На скриншоте мы уже немного поменяли настройки, потому что решили использовать пайплайн, описываемый в JenkinsFile (синтаксист). Помимо описания параметров, тулзов и окружений, можно выделить следующие шаги сборки: сборка кода, запуска тестов и составление отчета о прогоне (про это чуть позже). Вот примерно так у нас выглядит запуск тестов:
        Его (этот шаг) мы скопировали, воткнули в JenkinsFile, чтобы frontend и получили автоматический запуск тестов при каждой сборке. Хорошим тоном будет добавить в параметры сборки опцию выключения этих тестов, потому что зачастую они занимают слишком много времени.

        В результате получается вот такая красивая картинка пайплайна запуска тестов:
        Allure отчеты
        Заключительным этапом построения архитектуры автотестов является отчетность. Как нам узнать какие именно тесты упали? Почему они упали? Сколько прошло успешно?

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

        Изначально Allure уже интегрирован в Selenide и должен работать по умолчанию, но в нашем случае не все было так просто, скриншоты не прикреплялись, и пришлось отдельно описать Listener and Watcher:
        Еще добавим в JenkinsFile шаг составления отчета:
        И, в принципе, готово.

        Локально собирать красивый отчет можно командой «allure serve allure-results», а в Дженкинсе напротив каждой сборки появляется дополнительная кнопочка. В итоге вся информация о прогоне записывается в отчет: окружение, настройки браузера, список тестов, аналитика по успешному/не успешному запуску, ошибки и логи, да еще и красивый скриншот:
        Картинка для примера, потому что реальные данные проекта в вакууме шарить нельзя :)
        Выводы
        1
        Автоматизация будет полезна для проекта в случае, если ее правильно делать. Нужно помнить, что это не просто простыня кода, которая протыкивает те или иные места приложения, а организованная понятная структура. Не нужно автоматизировать все подряд, залог хороших тестов - актуальный скоуп, автоматизация которого принесет больше пользы, чем отнимет времени и сил.
        2
        Чем больше разноплановых шагов в тесте - тем сложнее его автоматизировать и тем сложнее найти баг в случае падения этого автотеста при запуске.
        3
        Не забываем подготавливать тестовые данные перед прогоном и чистить их сразу после. Как гласит всем известная истина: «Тесты должны быть независимы друг от друга», а если они еще и каждый раз используют разные данные, то мы получаем большее покрытие.
        4
        Недостаточно просто написать автотесты, нужно грамотно встроить их в процесс поставки продукта, чтобы они могли наносить максимальную пользу.
        О чем подумать дальше

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