Эволюция стратегий тестирования — хватит быть обезъяной

в 6:54, , рубрики: testing, web-разработка, Разработка веб-сайтов, тестирование, Тестирование IT-систем, Тестирование веб-сервисов

image

В этой серии статей я хочу описать наш опыт создания полностью автоматизированной стратегии тестирования (без QA) веб приложения Nielsen Marketing Cloud, которую мы создавали последние несколько лет.

В центре разработки Nielsen Marketing Cloud мы работаем без какого-либо ручного тестирования как новой функциональности, так и регрессий. И это дает нам большое количество преимуществ:

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

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

Но тут возникает вопрос на миллион долларов — как эффективно автоматизировать тестирование?

Часть 1 — Как делать не надо

Когда большинство разработчиков слышат «автоматизированное тестирование» они думают «автоматизация поведения пользователя» (end to end тесты с помощью Selenium) и мы тоже не были исключением из этого правила.

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

В итоге решение было принято — давайте писать кучу end to end тестов через Selenium!
Это казалось хорошей идеей. Но результат, к которому мы в итоге пришли был не таким радостным. Вот проблемы, с которыми мы столкнулись:

1. Нестабильные тесты

В какой-то момент, когда мы написали довольно большое количество end to end тестов, они начали падать. И падения были не постоянными.

image

Что делают разработчики, когда они не понимают почему случайно упал тест? Правильно — они добавляют sleep.

Начинается это с добавлением sleep'а на 300мс в одном месте, потом на 1 секунду в другом, затем на 3 секунды.

В какой-то момент мы находим в тестах что-то вроде этого:

sleep(60000) //wait for action to be completed

Я думаю, что достаточно очевидно почему добавление sleep'ов плохая идея, да?*

*если все таки нет — sleep'ы замедляют работу тестов и они постоянные, что означает что если что-то пойдет не так, и какая-то операция займет больше времени чем планировалось — ваши тесты упадут, то есть они будут не стабильными и не детерменированными.

2. Тесты работают медленно

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

Когда что-то работает медленно — разработчики обычно будут избегать этого, так что никто не будет запускать тесты на локальном окружении и код будет пушиться в систему контроля версий с надеждой, что CI будет зеленым. Но это не так. И CI красный. И разработчик уже ушел домой. И…

3. Падение тестов не информативно

Одна из самых больших проблем наших end to end тестов, что если с ними что-то не так, мы не можем понять в чем проблема.

И проблема может быть ГДЕ УГОДНО: окружение (помним, что ВСЕ части системы являются частью уравнения), конфигурация, сервер, фронтенд, данные или просто не стабильный тест (не достаточно sleep'ов).

И единственная вещь, которую вы увидите:

Эволюция стратегий тестирования — хватит быть обезъяной - 3

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

4. Данные для тестов

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

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

5. Динамический пользовательский интерфейс

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

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

Эволюция стратегий тестирования — хватит быть обезъяной - 4

6. Давайте построим наш собственный фреймворк

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

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

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

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

Итог

Конечно, некоторые проблемы могут быть частично решены (паралельный запуск тестов, снятие скриншотов при падении тестов, и т.д.), но в результате этот набор end to end тестов стал очень проблематичным, сложным и дорогим в поддержке.

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

В результате у нас:

  • тысячи end to end тестов
  • 1.5 часа на один запуск (20 минут при параллельном запуске)
  • падают почти каждый день и когда они красные — нам приходиться тестировать вручную
  • затрачивается куча времени разработчика для воспроизведения и исправления проблем с тестами
  • 30 тысяч строк кода в end to end тестах

Итоговый результат, который мы получили известен как "Антипаттерн рожка мороженного".

Эволюция стратегий тестирования — хватит быть обезъяной - 5

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

Автор: Mystetskyi Vlad

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js