Мигающие тесты

Прочитал я тут у Максима про мигающие тесты и захотелось мне вкинуть свои 5 копеек. Я не буду рассказывать, почему такие тесты возникают или что с ними делать (на эту тему и так довольно много рассказано и написано), а хочу поговорить про более серъёзную (на мой взгляд) проблему - где взять время чтобы ими заниматься?

Что сделали мы?

Мы сделали автотесты неотъемлемой частью процессов разработки и релиза. Это означает:

  1. Разработчик может вмержить изменения только если все тесты успешно выполнились на его ветке кода
  2. Чтобы изменения выехали в продакшн, тесты должны успешно выполниться на “продакшн” ветке
  3. Это один и тот же набор тестов

Если посмотреть немного шире, это адаптация нескольких практик из ДАО Тойота:

Любая операция на конвейере выполняется в соответствии с понятием Jikotei Kanketsu — она обеспечивает «завершенность и качество, встроенное в процесс»: на каждый последующий этап передается только качественный продукт. Для этих целей служит метод Poka-yoke — это использование приспособлений, не позволяющих продолжать работу, если операция выполнена неверно или не до конца. А чтобы дефект был вовремя локализован и устранен, используется сигнальная система Andon — часть принципа интеллектуальной автоматизации Jidoka, позволяющей внедрять устройства, останавливающие работу при возникновении нарушений. В этом и заключается особенность производства «Тойоты» — нельзя передавать процесс с отклонениями на следующий участок и потом доделывать. Сотрудники обязаны доложить начальству о любом отклонении, неважно, дефект ли это или мелочь вроде упавшего инструмента. Ведь андон — эффективное средство для выявления проблемы и ее анализа (принцип Hansei). Вопреки слухам, в момент активации андона конвейер не останавливается. Если бригадир успевает решить все вопросы в пределах проблемного производственного участка, то конвейер едет дальше. В противном случае конвейер останавливается. Если на производстве возникают повторяющиеся проблемы, то начинается расследование с участием бригадира и других руководителей для выяснения причин и поиска решения.

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

Допустим, один из тестов начал падать каждый 4-й раз. Это означает, что мои изменения уедут в продакшн сегодня с вероятностью чуть большёе 50% (0.75 x 0.75 = 0.5625). Если хотя бы один из билдов упадёт - считай что день потерян - перезапуск теста - это ещё от 30 минут до часа (при условии что он будет успешным!), а ещё мы обычно не мёржим код в продакшн ветку после 4-х вечера и не выкатываем изменения после 5-и.

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

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

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

План действий

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

  1. Назначается выделенный разработчик, который занимается исключительно проблемным тестом. Это может быть волонтёр - например, у нас в команде часто само-выдвигается разработчик, который хорошо знаком с мигающим тестом и знает как быстро его починить или хотя бы куда копать. Если желающих нет, это обычно разработчик, занимающийся на этой неделе техническим долгом.
  2. Если за прошедший день не было ни одного успешного релиза (мы обычно выкатываем от 2х до 5-и релизов в день), ответственный разработчик может запретить внесение изменений в продакшн ветку. Конкретно этот шаг имеет очень интересные последствия. Во-первых, это уменьшает количество изменений, которые выедут в продакшн после починки тестов. Меньше изменений - меньше риск что что-то пойдёт не так. Во-вторых, чем дольше основная ветка остаётся заблокированной, тем большему числу разработчиков становится нечего делать и они начинают подключаться к диагностике и починке тестов, тем самым ускоряя эту самую починку.
  3. Если дело совсем труба - например, начали мигать несколько тестов сразу и вероятность выкатить что-либо в прод близка к 0 - команда объявляет ЧП и начинает дружно чинить тесты. Никакие изменения, не связанные непосредственно с починкой тестов не принимаются.
  4. После починки тестов, ответственный разработчик может оставить продакшн ветку заблокированной для всех, кроме себя. В течении одного или нескольких последующих дней, он берёт на себя роль релиз менеджера - расставляет приоритеты для изменений, которые готовы к выкладке в продакшн, и вливает их в основную ветку небольшими группами (или даже по одному). Меньше изменений - меньше риск что что-то пойдёт не так.

Перезапуск и карантин

Можно/нужно ли перезапускать тесты? Я считаю что нет. Перезапускаю ли я тесты? Да =). Да, потому что я не робот, а человек. Иногда мне проще клацнуть “rerun failed”, чем разбираться в проблеме. Я категорически против и никогда не делал атоматических перезапусков мигающих тестов - это заметание мусора под ковёр.

Можно/нужно ли иметь карантин для тестов? Я считаю что нет, и у нас его нет. Если вы игнорируете результаты некоторых тестов - зачем их вообще запускать? А если вы их не запускаете - зачем их вообще держать? Само слово “карантин” подразумевает фиксированный отрезок времени, в течении которого что-то должно быть изолированно. На практике, такой фиксированный отрезок времени обычно превращается в “когда руки дойдут”. А когда руки доходят - тесты там настолько устаревают, что проще их удалить, чем пытаться разобраться, почему же они стали падать. Поэтому вместо карантина я предпочитаю “чинить, пока горячо”.

Вместо заключения

Я понимаю, что всё вышеописанное довольно экстремально и подходит не всем.

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

Наверняка найдётся множество других причин, технических или организационных, почему это не будет работать у вас. Но из моего опыта, описанная система крайне эффективна. Мне больше не нужно “выбивать” время для работы над улучшением тестов - без “зелёных” тестов не будет релизов, а без релизов встаёт прогресс по моим задачам. Важный момент здесь - решение о релизе принимает машина, а не человек. А с машиной спорить бесполезно - ей всё равно, что “упал тест не относящийся к моим измененим” или “у меня дедлайн”. Нет тестов - нет мультиков (с).

comments powered by Disqus