APPSFLYER DEVCONNECT. 26.07 Olympic Hall
×Закрыть

Автоматизация тестирования: как избежать распространенных ошибок

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

Быть или не быть

Вам гарантированно нужна автоматизация тестирования, если:

  • У вас проект длительностью в год или больше. Количество тестов, которые нужно прогонять в рамках регрессии, стремительно растет, а рутину нужно искоренять в первую очередь. Тестировщики должны тестировать, а не проходить тест-кейсы.
  • У вас распределенная команда разработки либо в команде больше двух разработчиков. Разработчик должен быть уверен, что его изменения не сломают чужой код. Без авто-тестов он узнает об этом в лучшем случае через день-два, в худшем — от пользователей.
  • Вы поддерживаете несколько версий продукта и выпускаете патчи и сервиспаки под каждую из них. Тут все очевидно: тестирование на разных конфигурациях — это рутина, а рутину надо искоренять.
  • Вы разрабатываете сервис, основная задача которого — обработка и трансформация всевозможных данных. Заниматься ручным вбиванием в систему данных и визуальным анализом результатов или отправкой запросов и анализом ответов — это вообще не то, чем должны заниматься живые люди каждый день.
  • У вас аджайл с короткими итерациями и частыми релизами. Времени на ручной прогон регрессии в рамках спринта катастрофически нет, а знать, что всё в порядке в тех местах, куда не лазили тестировщики, необходимо.

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

Зачем вообще нужны авто-тесты

Любая автоматизация нужна, чтобы избавить человека от рутинной работы. Автоматизация тестирования — в том числе. Однако существует также ошибочное мнение, что авто-тесты должны полностью вытеснить труд ручного тестировщика, и тестировать продукт должны скрипты. Это, конечно же, ерунда. Никакой скрипт пока не в силах заменить живого человека. Никакой скрипт пока что не умеет тестировать. Всё что умеет скрипт — это повторять запрограммированные человеком действия и сигнализировать, что что-то пошло не так, то есть делать простые проверки. И скрипт умеет делать это быстро и без участия человека.

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

Почему ожидания не оправдываются

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

Управленческие решения — это тема для отдельной статьи, а пока я просто выделю самые вредные ошибки без объяснений:

  • Попытка сэкономить на найме специалистов в области автоматизации. Если менеджер считает, что он может отправить своих тестировщиков на курсы по Selenium и они ему сделают автоматизацию, то он не прав.
  • Попытка внедрить автоматизацию без грамотно продуманной стратегии и планирования, типа «Давайте будем внедрять, а там посмотрим». Или чего хуже — автоматизация ради автоматизации: «У соседа есть, и мне нужно; зачем не ясно, но нужно».
  • Слишком поздний старт: тесты начинают автоматизировать только тогда, когда тестировщики уже совсем загибаются.
  • Убеждение, что дешевле нанять студентов, которые будут кликать регрессию руками (то есть вообще не делать автоматизацию, притом что присутствуют все признаки проекта, которому нужна автоматизация).

Под инженерными решениями я понимаю те решения, которые принимают инженеры при разработке и внедрении стратегии автоматизации. Это выбор инструментов, видов тестирования, фреймворков и т.п.

Пройдемся по некоторым моментам с инженерной точки зрения.

Почему автоматизация только UI-тестов — зло

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

UI-тесты — это то, что делают тестировщики, это естественный путь тестирования приложения. Более того, это симуляция того, как пользователи будут взаимодействовать с приложением. Казалось бы, это идеальный и единственно верный вариант, и именно его надо применять в автоматизации в первую очередь. Но есть, как говорится, нюанс:
— UI-тесты нестабильны;
— UI-тесты медленные.

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

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

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

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

Что же делать

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

Первое, что нужно в общем случае — это договориться с разработчиками, чтобы они не забывали прописывать для элементов уникальные атрибуты, по которым инструмент автоматизации может их однозначно идентифицировать. То есть, нужно по максимуму отказаться от пятиэтажных xPath-выражений или CSS-селекторов, и, по возможности, везде использовать уникальные id, name и т.п. Это должно быть явно прописано в девелопмент-гайдах и выступать одним из пунктов в definition of done для разработчиков. Тогда даже в случае капитального переколбаса пользовательского интерфейса у вас есть шанс отделаться легким испугом.

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

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

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

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

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

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

Третье и самое радикальное — создавать как можно меньше UI-тестов. Меньше тестов — раньше получаем результат их прогона.

Пирамида тестирования

Все помнят знаменитую пирамиду тестирования?

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

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

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

Что происходит, когда тот же тест автоматизирован через UI? Всё так же надо ждать, пока соберется и задеплоится новая версия, потом ждать, пока завершатся тесты. Потом надо проанализировать результаты прогона. Если были проблемы — определить, где эти проблемы возникли: в самом тесте или в приложении. Потом нужно еще раз прогнать упавший тест руками, чтобы наверняка понять, в чем проблема. Завести тикет, подождать пока пофиксят, перезапустить тест, убедиться, что теперь тест зеленый, закрыть тикет. Опять же — от пары часов до пары дней/недель. Плюс только в том, что этот тест автоматический, и пока он работает, тестировщик тестирует что-то другое.

Другая история, когда есть автоматизированные тесты, которые используют API для общения с бек-эндом приложения. Тут уже есть вкусные варианты:

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

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

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

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

Комплексный подход

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

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

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

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

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

На уровень UI-тестов выносятся исключительно приемочные тесты, так называемые Happy Path или End-To-End сценарии, которые показываются во время демо. Это относится как к веб-, так и к мобильным приложениям.

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

Резюме

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

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

25 комментариев

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

Есть пару неточностей.

Тестировщики должны тестировать, а не проходить тест-кейсы.
Прохождение тест кейсов это и есть тестирование в практическом смысле.
Всё что умеет скрипт — это повторять запрограммированные человеком действия и сигнализировать, что что-то пошло не так, то есть делать простые проверки.
Это и есть тестирование и ничего больше, то есть скрипт — тестирует.
То есть, нужно по максимуму отказаться от пятиэтажных xPath-выражений или CSS-селекторов, и, по возможности, везде использовать уникальные id, name и т.п.
CSS оптимизация не позволяет например везде использовать уникальные id — это значит криво использовать возможности CSS только лишь для удобства тестировщика.
Прохождение тест кейсов это и есть тестирование в практическом смысле.
В практическом смысле, тестирование это интеллектуальная деятельность. Тестировщик, в процессе тестирования, задействует все известные и доступные ему способы для нахождения проблемы. Тест кейсы тут выступают как вспомогательный инструмент, чтобы привести систему к определенному состоянию. Можно написать сотни крутых тест кейсов, и в итоге все равно пропустить какой то очевидный баг, который не проявляет себя при выполнении шагов из тест кейса, но прекрасно ловится думающим тестировщиком, который именно тестирует, а не просто проходит тест кейсы.
Это и есть тестирование и ничего больше, то есть скрипт — тестирует.
Скрипт проводит проверки. Он не тестирует, он проверяет. Тестирование как процесс невозможно запрограммировать (пока еще нет такого ИИ). Верификацию можно, тестирование нет )
CSS оптимизация не позволяет например везде использовать уникальные id — это значит криво использовать возможности CSS только лишь для удобства тестировщика.
Нет, это значит использовать уникальные идентификаторы там где это возможно, при чем это может быть не только id, но и уникальная комбинация нескольких элементов и/или их атрибутов. Главное чтобы это было предсказуемо и стабильно.

Я кажется понял — для Вас тестирование имеет какой-то-сакральный смысл). По последнему пункту соглашусь — грамотное сочетание атрибутов и других CSS артефактов способно дать оптимальный компромис.

Я кажется понял — для Вас тестирование имеет какой-то-сакральный смысл).

Ага, с гуманистическим уклоном ))

id использовать крайне не рекомендуется.
А

уникальная комбинация нескольких элементов и/или их атрибутов
в какой-то момент может перестать работать.

Сейчас в мире фронтенда модульный подход. Пишутся отдельные компоненты, они тестируются.
BEM, React. И даже Angular.

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

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

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

А как по мне, то эта статья всего лишь вводная часть. Написано кстати, легко и понятно, так что респект и спасибо Yaroslav!!! А на счёт критики коллег, так я в этом вижу только одно — ЖДЁМ ПРОДОЛЖЕНИЯ В БОЛЕЕ ГЛУБОКОЕ ПОГРУЖЕНИЕ! Пишите Yaroslav!!! Спасибо!

Вы все правильно поняли ) Продолжение будет конечно. Спасибо за отзыв.

Я залишу кілька лінків на книги. Для тих хто хоче запустити автоматизацію в стилі «Взяв і зробив»
1. «Specification by Example» (Gojko Adzic) books.gojko.net/...specification-by-example
2. BDD in Action Behavior-Driven Development for the whole software lifecycle www.manning.com/books/bdd-in-action

Рекомендую уважно читати, надихатися і втілювати в життя усім хто страждає і відчуває біль на автоматищаційних проектах

На уровень API-тестов нужно опускать все функциональные тесты, которые тестировщики проводили на протяжении спринта. Негативные, позитивные, комбинаторные и т.п. Тем самым создается быстрый и стабильный пакет регрессионных тестов.
Это как? Я так понимаю, Вы говорите о manual UI tests. Каким образом Вы предлагаете заменить их API тестами? Часть логики перекрыть можно, не вопрос. Но как насчёт взаимодействия с самими контролами на странице? Например, проверить, что кнопка «поиска» становится активной после ввода выражения для поиска в форму?

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

В таком контексте — согласен. Но тогда это означает не

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

Для тех, кто еще не успел прочитать(краткое содержание)
ищем проблему

Почему автоматизация только UI-тестов — зло
Нестабильны
Медленные
ищем решение
Что же делать
Стабилизируем.
Ускоряемся.
отличная статья, Капитан.
Test Driven Development — это уже даже не рекомендация, это должно исходить от разработчика по умолчанию. Только тогда можно избежать головняков при рефакторинге и типичных проблем разработки в больших командах.
Вы здесь точно имеете в виду не юнит-тесты, а именно TDD? Слишком уж категорично для такой редкой и неоднозначной практики.

С чего вы взяли что TDD редкая и неоднозначная практика ?

Почему 95% разработчиков не используют TDD? dou.ua/forums/topic/17764

Не знаю по поводу 95 %, но из моего опыта — почти десяток проектов, больших и маленьких — ни одного примера полноценного использования ТДД.
Я не к тому, что это плохо. Просто далеко не всегда уместно и оправданно.

Там же прямо в комментах есть ответ — «отсутсвие понимания такого процесса разработки в целом + отсутствие практического опыта успешного применения ТДД» Отсутствие понимания и опыта работы не делает подход «неоднозначным», а практику «редкой». Получается, что у нас 95% незрелых программистов. (на самом же деле гораздо меньше, конечно :) ) А уместно и оправдано оно всегда, даже для простых проектов, просто это как в анекдоте про — Вам нравятся кошки? Нет? Да вы просто не умеете их готовить.

Если 95% не используют — значит редкая.
Вы считаете всех, кто не использует эту практику незрелыми. А можете допустить, что люди у которых есть понимание TDD принимают осознаннное решение ее не применять?
Это почти как с автотестами — не на каждом проекте окупятся.
Самая простая причина — динамичное развитие проекта, когда цена бага невысока, а написание двойных объемов кода дороже.

Люди, у которых есть полное понимание TDD никогда не примут осознанного решения не применять. Потому что что дело совсем не в двойном объеме кода. Дело в том, что разработка по TDD происходит реально быстрее чем без (IDE уже делает 50% дурной работы за человека). А вот незрелый девелопер, который не понимает как можно разрабатывать быстрее, при том что надо писать тесты, тот таки может сослаться на «динамично развивающийся проект». TDD это в первую очередь для разработчика. Другое дело, когда TDD изначально небыло и теперь просят написать юнит-тесты на уже существующий код, при этом архитектура абсолютно не тестабельная, и это реально гемор и дурная работа.

Жаль дизлайков нет.

Кину лучше в комменты годную темку, вместо этой водянистой, чтобы тем, кто прочитал было не жалко времени:
automated-testing.info/...-testirovaniya-po/1546/31

Не подумайте превратно, но это просто еще одная статья из миллиона подобных про автоматизацию. Масло масляное, вода водянистая — это я про конкретику в сией статье. Почему бы не сделать обзор инструментов, запустить техно холивар, рассказать что ВЫ конкретно применяете для тестирования различных уровней (UI, API, etc). Написано то не плохо, только смысла мало.

Это тоже будет. Не все сразу.

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

Подписаться на комментарии