Опыт внедрения автоматизации в процесс ручного тестирования на примере Android-приложения

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

    Совместно с нашими партнёрами мы активно разрабатываем, тестируем и поддерживаем семейство приложений для разных платформ: Android, iOS, Windows. Приложения активно развиваются, вместе с чем увеличивается и объём тестирования, в первую очередь — регрессионного.

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

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

    Поехали!

    Отправная точка


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

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

    Проблема №1: много регрессионных тестов


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

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

    Проблема №2: нужно тестировать на всех версиях мобильной ОС


    Важным требованием является работоспособность наших мобильных приложений на большом диапазоне версий операционной системы. Например, в случае Android на момент написания статьи — это уровни API от 17 до 28.

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

    Решение: внедрить автоматизацию в процесс ручного тестирования



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

    В то же время мы прекрасно осознаём, что невозможно и ненужно пытаться полностью искоренить ручное тестирование автоматизацией. Критическое мышление и человеческий взгляд трудно чем-то заменить. На эту тему есть хорошая статья в блоге Майкла Болтона The End of Manual Testing (или перевод от Анны Родионовой).

    Мы подумали, что будет полезно иметь набор автоматизированных тестов, которые покрывают стабильные части приложения, а в дальнейшем — писать тесты на найденные баги и новый функционал. При этом мы хотим связать автотесты с существующими тестовыми наборами в нашей системе управления тестами (мы используем TestRail), а также дать возможность тестировщикам легко запускать автотесты на облачных физических устройствах (в качестве облачной инфраструктуры мы выбрали Firebase Test Lab).

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

    Что мы хотим получить в итоге:

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

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

    Общая схема реализации решения


    Но сначала — общая схема того, что у нас получилось:

    image

    Автотесты запускаются двумя способами:

    1. Из CI после merge или pull request в master.
    2. Тестировщиком вручную из веб-интерфейса Jenkins Job.

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

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

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

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

    Теперь перейдём к обещанному описанию реализации.

    1. Автотесты


    Инструменты


    Мы использовали 3 инструмента для взаимодействия с пользовательским интерфейсом:

    • Espresso.
    • Barista.
    • UI Automator.

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

    Доступ к коду Android-приложения нужен для того, чтобы в тестах вызывать его методы. Мы можем заранее подготовить наше приложение к определённому тесту, запустив его в нужном состоянии. Иначе нам нужно достигать этого состояния через интерфейс, что лишает тестов атомарности, делая их зависимыми друг от друга, и просто съедает много времени.

    В ходе реализации к Espresso добавился ещё один инструмент — UI Automator. Оба фреймворка являются частью Android Testing Support Library от Google. С помощью UI Automator мы можем взаимодействовать с различными системными диалогами или, например, с Notification Drawer.

    И последним в нашем арсенале стал фреймворк Barista. Он является обёрткой вокруг Espresso, избавляя вас от boilerplate-кода при реализации распространённых пользовательских действий.

    Помня о желании иметь возможность переиспользования решения в других приложениях, важно отметить, что перечисленные инструменты предназначены исключительно для Android-приложений. Если вам не нужен доступ к коду тестируемого приложения, то, вероятно, вы предпочтёте использовать другой фреймворк. Например, очень популярный сегодня Appium. Хотя и с ним можно попробовать достучаться до кода приложения с помощью бэкдоров, о чём есть хорошая статья в блоге Badoo. Выбор за вами.

    Реализация


    В качестве паттерна проектирования мы выбрали Testing Robots, предложенный Джэйком Уортоном в одноимённом докладе. Идея этого подхода схожа с распространённым шаблоном проектирования Page Object, применяем при тестировании веб-систем. Язык программирования — Java.

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

    Рассмотрим простой пример. Описываемый фрагмент — несколько полей для ввода данных и кнопка действия:

    image

    Код самого теста функциональности логина:

    image

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

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

    В вышеупомянутом докладе Джейк Уортон приводит вариант реализации на языке Kotlin, где конечны. Мы уже попробовали его на другом проекте и нам очень понравилось.

    2. Интеграция с системой управления тестами


    До внедрения автоматизации мы вели всё наше тестирование в системе управления тестами TestRail. Хорошей новостью стало то, что существует достаточно неплохой TestRail API, с помощью которого мы смогли связать уже заведённые в системе тест-кейсы с автотестами.

    В ходе выполнения тестового запуска с помощью JUnit RunListener отлавливаются разные события, такие как testRunStarted, testFailure, testFinished, в которых мы и отправляем результаты в TestRail. Если вы используете AndroidJUnitRunner, то ему нужно сообщить о вашем RunListener определённым образом, описанным в официальной документации.

    Вам также нужно установить связь с различными сущностями TestRail по их ID. Так, для связи теста с соответствующим тест-кейсом мы создали простую аннотацию @CaseId, использование которой показано в примере реализации теста выше.

    Код реализации самой аннотации:

    image

    Остаётся только достать её значение в нужном месте из Description:

    image

    3. Ручной запуск автотестов на облачных устройствах


    Параметризация запуска в Jenkins Job


    Для организации ручного запуска автотестов мы используем Free-style Jenkins Job. Этот вариант был выбран, так как в компании уже имелся определённый опыт подобной работы с Jenkins Job в других областях, в частности у DevOps-инженеров, коим они с радостью поделились.

    В Jenkins Job выполняется скрипт на основе переданных из веб-интерфейса данных. Таким образом реализуется параметризация тестовых запусков. В нашем случае Bash-скрипт инициирует запуск тестов на облачных устройствах Firebase.

    Параметризация включает в себя:

    • Выбор нужных APK путём указания номера соответствующего билда или загрузки их вручную.
    • Ввод всевозможных тестовых данных.
    • Ввод дополнительных кастомных данных для TestRail.
    • Выбор облачных физических устройств, на которых будут выполняться тесты, из списка доступных в Firebase Test Lab.
    • Выбор тестовых наборов, которые будут выполнены.

    Рассмотрим часть веб-страницы нашей Jenkins Job на примере интерфейса выбора устройств и тестовых наборов:

    image

    Каждый элемент, где можно ввести или выбрать какие-либо данные, реализуется специальными Jenkins-плагинами. Например, интерфейс выбора устройств сделан с использованием Active Choices Plugin. С помощью groovy-скрипта из Firebase получается список доступных устройств, который затем отображается в нужном виде на веб-странице.

    После того, как все нужные данные введены, запускается соответствующий скрипт, за ходом выполнения которого мы можем наблюдать в разделе Console Output:

    image

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

    Итоговая тестовая матрица в Firebase Test Lab


    Матрица устройств в Firebase содержит распределение тестов по устройствам, на которых они выполнялись:

    image

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

    Мы выбрали Firebase, так как уже использовали этот сервис для решения других задач, и нас устраивает ценовая политика. Если уложиться в 30 минут чистого времени на тестирование в сутки, то платить не нужно вовсе. Это может быть дополнительной причиной, по которой важно иметь возможность запускать только определённые тесты.

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

    4. Переиспользование


    Как всё это можно использовать в дальнейшем? С точки зрения кодовой базы данное решение применимо только для Android-приложений. Например, в ходе реализации у нас появились вспомогательные классы EspressoExtensions и UiAutomatorExtensions, где мы инкапсулируем различные варианты взаимодействия с интерфейсом и ожидание готовности элементов. Сюда же относится и RunListener-класс, отвечающий за интеграцию с TestRail. Мы уже вынесли их в отдельные модули и используем для автоматизации других приложений.

    Если говорить о других платформах, то полученный опыт может быть очень полезен для того, чтобы выстраивать и реализовывать аналогичные процессы. Этим мы сейчас активно занимаемся на iOS-направлении и подумываем о Windows.

    Заключение


    Существует множество вариантов реализации и использования автоматизации тестирования. Мы придерживаемся мнения, что автоматизация — это в первую очередь инструмент, который призван облегчить традиционный процесс «человеческого» тестирования, а не искоренить его.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 0

    Only users with full accounts can post comments. Log in, please.