43. Итого
6500 тысяч тестов
Общее время прогона — 40 минут
Требует усилий только одного разработчика
Результаты представлены максимально доступно
Релиз минимум раз в месяц
Editor's Notes
Меня зовут Иван Медведев, я разработчик сервиса «Бухгалтерия.Контур». Мы, как можно понять из названия, хотим сделать онлайн бухгалтерию для малого бизнеса.
Так как наша целевая аудитория — это малый бизнес, в первую очередь мы должны решать его задачи. Что нужно малому бизнесу?
В первую очередь ему нужны деньги. И никакая бухгалтерия будь то онлайн или оффлайн, ему не нужна. Однако есть еще и государство.
Государству тоже нужны деньги. Чтобы случайно не отдать государству лишнее — нужна бухгалтерия
Однако мы не можем просто так взять и сделать всю бухгалтерию целиком, потому что она очень большая. Если взять только системы налогооблажения: ОСНО, УСН, ЕНВД, ЕСХН, патент, ... — будет уже вполне достаточно. По каждой из них куча форм отчетности перед налоговой. А кроме того есть еще и первичные документы, сотрудники и много, много, много всего
Поэтому мы собираемся делать ее итеративно. Начнем с минимально жизнеспобного продукта, а дальше будем постпенно его усложнять. Чтобы этот процесс не затянулся во времени на 15 лет, нам необходимо делать частые релизы.
И как только мы начинаем говорить о релизах, возникают проблемы. Хорошо, когда релиз первый. У вас было 0 «функций» стала одна. Вы ее проверили — релиз готов. Мы гарантированно не сломаем уже существующую функциональность. Однако на практике, релиз почти всегда не первый. И когда ваш разработчки делает очередную фичу, он глубоко уверен, что ничего не сломает.
Он ошибается.
Однако, чаще разработчики все же понимают, что могут что-то сломать своими изменениями, но сознательно идут на это. Потому что знают, что в целом они улучшают код.
Как можно проверить, что после очередного изменения все работает? Очевидно. Проверяем первую страницу, вторую страницу, третью страницу..., первый лайтбокс, второй лайтбокс ..., ссылки, кнопки и все-все-все... Когда мы закончим, например через сутки, можно вспомнить, что браузеров много. Даже для вашего тестировщика это очень непростая задача.
Разумеется, разработчик делать этого никогда не станет
Значит нужно автоматизировать. Однако, нам нужно не просто автоматизированное тестирование, а кое-что больше. Вернемся к тому что мы делаем. Мы делаем онлайн бухгалтерию для МАЛОГО БИЗНЕСА
Когда мы слышим слово «бухгалтерия» — в первую очередь мы представляем себе бухгалтера. Однако, наш продукт предназначен не для бухгалтеров. И для того, чтобы понять нашу целевую аудиторию, мы провели исследование.
В результате которого выяснилось, что типичный предприниматель, скорее похож на хипстера.
Конечно же, в действительности, предприниматели, выглядят вот так. Но они мало пользуются интернетом.
Что же нужно хипстеру? 1С? нет
Хипстеру нужен iPhone . Почему? Потому что он удобный и красивый. Следовательно, чтобы наша бухгалетрия пользовалась популярностью, нужно делать нечто похожее. Значит нам нужны хорошие интерфейсы.
Хорошие интерфейсы — это очень сложно. Их тяжело реализовывать. Это, как правило, приводит к большому количеству ошибок. Следовательно нужно автоматически тестировать интерфейсы. А значит нужно функциональное тестирование. Люди, которые в своей жизни написали хотя бы один функциональный тест, знают, что они проходит на порядки дольше модульных. Настолько, что запускать тесты прямо перед запуском становится накладно.
Подведем небольшой итог. Для того, чтобы сделать бухгалерию нам нужно постоянно выпускать новые фичи, а следовательно часто релизиться. Для того, чтобы релизы были качественными нужно писать много долгих функциональных тестов и прогонять их перед каждым релизом, что, в свою очередь, сильно усложняет и растягивает во времени процесс обновления. Решение нашей проблеммы давно известно, и имя ему Continuous Integration.
Если вы не знаете, что такое Continuous Integration , то ничего страшного в этом нет. Просто откройте гугл и почитайте. Там же можно найти ссылки на готовые инструменты. Один из них – TeamCity. Это очень удобный для небольших проектов сервер непрерывной интеграции с большим количеством уже реализованных «прямо из коробки» функций. Поэтому, мы начали его использовать
В тот момент у нас было всего-лишь 90 функциональных тестов. И мы развернули три конфигурации и стали прогнять наши тесты на Chrome, FF и IE . Таким образом, перед очередным релизом нам не нужно было больше запускать все тесты и ждать пока они пройдут. TeamCity делал это за нас. Таким образом нам требовалось только посмотреть на упавшие и починить их. Как правило, их было немного.
Однако, время шло. И мы развивали наш сервис. Он стал сложнее. Мы реализовали все новые и новые интерфейсы. В них было сокрыто много нюансов, и как следствие у нас стало значительно больше тестов. Точнее, их стало 300.
Это привело к тому, что время их выполнения сильно увеличилось. И если ситуация с тестами в Chrome -е нас устраивала, то ситуация с тестами в IE была критической. Это приводило к тому, что перед релизом мы видели уже неактуальное состояние системы. И если даже TeamCity показывал, что у нас все хорошо, то за пять часов с момента последнего запуска ситуация могла очень сильно поменяться. Пришлось принимать меры.
Вообще говоря, 99% ошибок возникают не из-за особенностей отдельно взятых браузеров. В нашем случае их причина — неправильно реализованная бизнес-логика приложения. Поэтому мы отказались от того чтобы прогонять тесты в медленных браузерах.
Но у Chrome –а была другая проблема. Примерно с 250 теста Chrome начинал вести себя не как Chrome . В нем происходила ошибка, после чего все оставшиеся 50 тестов успешно падали.
Мы стали перезапускать браузер через каждые 20 тестов.
Очевидно, что основных проблем, связанных с длительностью выполнения тестов мы не решили. И когда у нас стало 1000 тестов, то время их прохождения даже в Chrome стало 3 часа. Мы начали думать о том как решить эту проблему раз и навсегда. Самая первая мысль, которая пришла к нам в голову — это параллельный запуск. Однако, оказалось, что TeamCity не умеет делать это из коробки. Решение проблемы пришло внезапно.
Как устроены у нас тесты? Мы пишем их на C# как и само приложение. У нас есть отдельный проект с тестами. И те кто пишут на C# знают, что файл проекта представляет собой обыкновенный xml файл. Суть в том, что его можно модифицировать перед компиляцией, например, убирать некторые xml элементы. К чему это может привести? Если удалить какой-нибудь xml элемент из фрагмента показанного на слайде, то все классы из файла подключаемого в этом элементе (атрибут Include ) не попадут в итоговую сборку. По счастливой случайности, все тесты у нас находились в файлах, имена которых заканчивались на суффикс Test . Была случайность – сделаем из этого закономерность.
Предположим, что у нас есть кластер из трех машин и 30 файлов с тестами. Каждая машина знает свой порядковый номер в кластере. Таким образом, первая машина знает, что она должна прогонять тесты из первых 10 файлов, вторая — из вторых десяти файлов, третья — из третьих десяти файлов. Параллелить тесты научились.
Дело осталось только за вычислительнымии мощностями. Это очень простая проблема. Можно купить или арендовать сервер с каким угодно количеством виртуальных машин.
А можно сходить в магазин через дорогу и купить обыкновенные игровые компьютеры без видеокарт. Это реальная фотография нашей «фермы».
Чему мы научились? Мы научились всего лишь быстро прогонять тесты и наблюдать перед релизов актуальное состояние. Хорошо, когда тесты проходят. Все хуже когда тесты не проходят. Если у вас 100 тестов, то починить упавшие 2-3 штуки несложно. Если же у вас 10000 тестов, то починить упавшие 100 становится проблемой
Все усложняется еще и тем, что, скорее всего, последний раз тесты проходили только перед предыдущим релизом. С тех пор в коде было сделано много изменений и понять по какой причине тест перестал проходить становится очень сложно. На починку такого теста уходит существенно больше времени. Очевидно, что релиз в такой ситуации придется отложить
Чтобы такого не возникало, нужно следить за своими тестами постоянно, а не только перед релизом. Следовательно Continuous Integration должна все время находиться перед глазами. Можно заставить разработчиков, открыть браузер с TeamCity на одном из двух мониторов (у всех наших по два монитора). Но разработчики всегда найдут более эффективное применение второму монитору. Поэтому мы пошли в магазин через дорогу и купили телевизор. Повесили его под потолком, чтобы каждый разработчик мог просто поднять глаза и понять как обстоят дела с тестами.
Наш вам совет, покупайте телевизор по-больше
Оказалось, что поднять глаза очень непросто. Разработчику для того чтобы реализовать ту или иную фичу приходится сильно погружаться в контекст задачи. Это отнимает много времени и сил. Никто не любит выходить их контекста. Особенно для того, чтобы чинить упавшие тесты или компиляцию
Поэтому мы научили нашу систему говорить в прямом смысле этого слова. Теперь когда кто-нибудь ломает компиляцию – технический женский голос говорит: «Билд сломан, виноват Медведев» (если его сломал Медведев).
В итоге, чему мы научились? Мы научились делать быстрый прогон всех тестов и научились время от времени между релизами поднимать упавшие тесты. Однако, на практике оказалось, что тесты бывают не только упавшими или неупавшими. Они могут быть нестабильными. На локальной машине разработчика такой тест всегда пройдет, а вот на агенте, где его запускает TeamCity он время от времени падает. В чем может быть причина
В реальном мире большинство сервисов имеют период инициализации. Когда не все кэши загружены, не всё скомпилировано и т.д. и т.п. Запросы к сервису в таком случае могут выполняться на порядок дольше. Этого может хватить, для того, чтобы ваш тест упал по таймауту. Поэтому нужно обязательно разогревать тестовый стенд перед запуском тестов. Если вы, например, имеете дело с ASP.NET обязательно включите прекомпиляцию страниц и контролов. Разогревать нужно не только фронты. Backend тоже нужно разогревать.
Еще одна распространенная причина нестабильных тестов заключается в том, что у ваших агентов может случиться недостаток системных ресурсов, таких как оперативая память. Не факт, что каждому вашему тестовому агенту необходимо иметь по экземпляру сервиса требовательному к памяти. Может быть можно переконфигурировать тестовый стенд таким образом, что тяжелый сервис запускался в единственном экземпляре на отдельной машине? Также важным ресурсом является очередь операций к жесткому диску. Если у вас именно такая ситуация – купите SSD в магазине через дорогу.
Хотя подобные ухищрения позволяют в каких то случаях разобраться с нестабильными тестами, наверняка от их появления избавиться не удастся. А как можно решить эту проблему? Ведь если заставить разработчика, погруженного в контекст текущей задачи, выйти из этого самого контекста и заставить чинить нестабильный тест, вас как, минимум, неправильно поймут.
Поэтому у нас есть специальная переходящая роль. Она называется «дежурный инженер». Суть этой роли, заключается в том, чтобы остальные разработчики как можно реже выходили из контекста текущей задачи. Поэтому дежурный инженер отвечает за релиз, отвечает на вопросы техподдержки, и следит за Continuous Integration . Через две недели, дежурный инженер меняется. Кроме того, дежурство — это отличный способ для новичков узнать систему и погрузиться в разработку.