«Колёса Крыша Маркет» corporate blog
PHP
Web services testing
November 2018 15

История о том, как мы ускорили тесты в 12 раз

Ускоряйте тесты, говорили они.

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

Для тех кто не знает, компонентные тесты — это тесты которые полностью изолированы от глобального окружения и позволяют проверить те или иные кейсы, которые unit тест не смог бы охватить.

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

Ведь, в этом случае от тестов вреда больше, чем пользы, но избавляться вовсе и “забить” на тесты, далеко не лучший вариант :) Тогда, тимлидом была организована небольшая микро-команда в лице:

  1. Тимлида
  2. Backend разработчика
  3. QA инженера
  4. Админа

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

На момент начала разработки, у нас было 140+ функциональных тестов, которые запускались в несколько потоков под разные окружения (Frontend, Mobile, Backend) и проходили они ~5-7 минут; также нередко приходилось их перезапускать, чтобы добиться зеленой сборки. А падали эти тесты больше не из-за нового написанного кода, а из-за проблем в окружении, то есть, где-то API не ответил, где-то микросервис тестируемый упал и т.д. Это останавливало работу всего отдела, так как сборки запускались почти каждые 5-10 минут: кто-то пересобирал, кто-то пушил новый код…

После первой половины недели, пришли к тому, что будем “мокать” наше API и сторонние сервисы, что дало бы нам полностью изолированную среду тестирования. Но вставал вопрос: писать что-то своё или… Так вот, на этом “или” всё и завершилось — недолгими поисками, на своём пути я встретил — небольшую наработку в виде Mock сервера “http-api-mock”.

http-api-mock — легкий и не требующий установки mock сервер, написанный на языке Go с неплохой документацией.

Спустя сотни попыток запустить, а также вообще вникнуть в тему моков, мне всё же удалось переписать 1 функциональный тест, который создавал новое объявление на сайте и, пройдя все круги ада, убеждался, в том, что заголовок на странице соответствует заголовку в теле объекта.
Представьте себе, заработало! Переписанный тест оказался в 3 раза быстрее, чем предыдущий, так как здесь мы не проверяли создание, модерацию, а сразу же отдали из мока нужный объект объявления и выиграли на этом. Эта маленькая победа стала хорошим стимулом для дальнейшего развития этой темы, тем самым, спустя еще неделю, у нас был новый suite в codeception с названием “component”, который имел уже базовый helper класс для работы с нашим Mock сервером и запускался на тот момент у меня на песочнице.

Базовый класс-помощник умеет создавать объявление в виде json-файла в директории конфигов нашего mock-сервера, отдавать нужное объявление по id и т.д. Почти API.

Остальная магия ждала нас дальше — теперь оставалось настроить план сборок в bamboo. Чтобы наши тесты теперь проходили уже через наш CI&CD.

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

Для работы всей этой магии, нам пришлось добавить новые конфиг-файлы с новым адресом API и внешних сервисов, а также поднять копию базы mysql, ну и еще создать в build-плане новый таск с запуском нашего mock-сервера.

# Delete/Create network
docker network rm mock-kolesa-net;
docker network create --subnet=IP_ADDR/24 --gateway IP_ADDR_GATEWAY mock-kolesa-net;

# Docker run http-mock-kolesa
docker run \
--rm \
--name http-mock-kolesa -d \
-v ${CONFIG}/config/:/config \
-v ${CONFIG}/data/:/data \
--user $(id -u):$(id -g) \
--net mock-kolesa-net \
--ip IP_ADDR\
local-docker-hub.kolesa-domain.org:7979/build/http-mock-kolesa;

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

Время шло, тесты переписывались и вот 140 функциональных тестов превратились в 103 компонентных теста, которые проходят параллельно за ~30 секунд.



Из плюсов


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

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

Легко писать. Собственно, в процессе переписывания, многое решалось копированием кода из старого функционального теста в новый компонентный и подготовки для него endpoint-ов в Mock сервере.

Из минусов


Поддержка. Теперь каждый разработчик, который внёс изменения в возвращаемый ответ для определенного endpoint-а в API, также идёт в репозиторий с конфигами для mock-сервера и правит ответ там.

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

Результаты:


Тесты
Было: 140+ функциональных тестов = 5-7 минут.
Стало: 103 компонентных тестов = ~30 секунд.

Стабильность сборок
Было: Каждая третья сборка падала из-за каких-либо проблем.
Стало: Падает только когда разработчик поломал логику какого-то метода.

В дальнейших планах у нас переписывание acceptance (gui) тестов — также запускать их внутри контейнера и изолировать от остального окружения.
+28
10.3k 57
Comments 15
Top of the day