Монолит для сотен версий клиентов: как мы пишем и поддерживаем тесты

Темы:

  1. Наш процесс разработки
  2. Юнит-тесты
  3. Интеграционные тесты
  4. Тесты на API
  5. Прогон тестов

Процесс разработки

К сроку выкатывания фичи добавляется:

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

Нужны автотесты!

Unit-tests

Тесты на изолированные кусочки кода.

Сложно тестировать легаси. Для него делаем SoftMocks. Оно перехватывает все include/require в PHP-файле, подменяет подключаемый файл на другой.

Можно мокать любые методы: статические, приватные, финальные.

Проблема: SoftMocks расслабляют — можно писать плохо тестируемый код и всё равно покрыть его тестами. Решили правилами:

Правила проверяются на код-ревью.

Мутационное тестирование.

  1. берем код
  2. берем code coverage
  3. парсим код и генерируем мутации: меняем плюс на минус, true на false
  4. для каждой мутации прогоняем набор тестов:

    • если тесты упали — они хорошие
    • если тесты успешно прошли — они недостаточно эффективны

Для PHP есть готовые решения: Humbug, Infection. Но они несовместимы с SoftMocks. Поэтому написали своё.

Интеграционные тесты

Тестируем работу нескольких компонентов в связке.

Стандартный подход:

  1. Поднимаем тестовую БД
  2. Заполняем её
  3. Запускаем тест
  4. Очищаем БД

Есть проблемы:

Решение: DBMocks

  1. Методы драйверов DB перехыватываются с помощью SoftMOcks на setUp теста
  2. из запроса вытаскиваются db + table
  3. создаются временные таблицы с такой же схемой
  4. все запросы идут во временные таблицы
  5. потом на tearDown они удаляются

Результаты:

API-тесты

Обычно такие тесты требуют авторизованного пользователя. Его нужно создать перед тестом и удалить после. Это порождает риск нестабильности, потому что при создании пользователя есть репликация и фоновые задачи.

Решение: пул тестовых пользователей.

  1. Нужен пользователь
  2. ищем в пуле
  3. если нет — создаём
  4. после теста очищаем, потому что тест загрязняет пользователя

Тестовые пользователи в одном окружении с реальными? Зачем вообще их тестировать на бою? Потому что devel ≠ prod. Надо изолировать, иначе пользователи будут флиртовать с кучей фиктивных Олегов.

Путь 1: флаг is_test_user, по флагу изолируем внутри сервисов.

Путь 2: всех пользователей переселяем в условную Антарктиду и они там тусят друг с другом.

QA API

бэкдор для тестирования

Позволяют сменить пользователю неизменяемые данные, вроде даты регистрации.

Безопасность

Прогон тестов

Распараллелили тесты в TestCloud.

Как распределить тесты между потоками?

Как сделали:

Проблема: медленные тесты занимают ресурсы, не давая выполняться быстрым. Т.е. API могут занять весь Cloud.

Решение: разделили Cloud

Результат:

Какие тесты выполнять? Покажет code coverage.

  1. Получаем branch diff
  2. формируем список измененных файлов
  3. получаем список тестов, которые его покрывают
  4. запускаем прогон набора только из этих тестов

А где взять coverage?

Плюсы:

Минусы:

Итоги

Ссылки