Тесты для своего кода - что покрывать и как запускать
Заводим тесты там, где они окупаются: на расчётах, разборе форматов и правилах, которые сложнее одной строки.
Решение
Начинаем с кода без ядра:
// /local/lib/Price/Calculator.php - чистый расчёт, платформа ему не нужнаfinal class Calculator{ public function withDiscount(float $price, float $percent): float { return round($price * (100 - $percent) / 100, 2); }}// такой класс проверяется тестом за минуту и без единого запроса к базеПервыми тестируют функции, которым ядро не нужно. Расчёт скидки, разбор строки обмена, склейка адреса - именно здесь ошибки дороже всего и ловятся дешевле всего.
Поднимаем ядро там, где без него никак:
// bootstrap.php тестовdefine('NO_KEEP_STATISTIC', true);define('NOT_CHECK_PERMISSIONS', true);$_SERVER['DOCUMENT_ROOT'] = '/home/stend/public_html';require $_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_before.php';Тесту с базой ядро подключают одним файлом. Дальше в тесте доступны те же классы, что и в коде сайта, но и цена растёт: такой тест идёт секунды, а не миллисекунды.
Готовим и убираем данные:
protected function setUp(): void{ $this->iblockId = self::createTestIblock(); // свои данные, не боевые}protected function tearDown(): void{ CIBlock::Delete($this->iblockId); // и убираем за собой}Тест создаёт свои данные и убирает их за собой. Тест, опирающийся на «товар с номером 42», ломается в тот день, когда этот товар удалят, и вины кода в этом нет.
Запускаем на стенде:
cd /home/stend && ./vendor/bin/phpunit --testsuite unit # быстрые, без ядра./vendor/bin/phpunit --testsuite integration # медленные, с базой# на боевом сайте тесты не запускают: они пишут и удаляют данныеТесты живут на стенде, а не на живом сайте. Они создают и удаляют записи, а случайно запущенный на боевом сайте набор способен натворить дел за одну минуту.
Тестами закрывают то, что сложно проверить руками. Правило скидки, разбор чужого формата, границы периода - здесь тест окупается на первой же правке.
Вёрстку и вывод компонентов тестами не покрывают. Такой тест ломается от любой правки разметки и не ловит ничего полезного, а поддерживать его приходится вечно.
Тест, найденный сломанным после чужой правки, стоит починить сразу. Отключённый «на время» тест не включают уже никогда, а через полгода его никто и не помнит.
Первые тесты стоит написать на том куске кода, который уже ломался. Место, где ошибка стоила вечера разбора, - самый честный кандидат: там тест сразу показывает пользу, и спорить о нужности тестов больше не приходится.
Типичные проблемы
Тесты падают через раз.
Они опираются на данные боевого сайта, которые меняются. Тест создаёт свои данные и удаляет их за собой.
Набор тестов идёт по десять минут.
Все тесты поднимают ядро, даже те, которым оно не нужно. Быстрые и медленные тесты разводят по наборам.
На боевом сайте пропали записи.
Набор тестов запущен на живом сайте, и уборка данных сработала на его записях. Тесты запускают только на стенде.
Тест сломался от правки вёрстки.
Он проверяет разметку компонента, а не поведение кода. Вывод тестами не покрывают.
Половина тестов отключена.
Их отключали по одному, когда они мешали выкладке. Сломанный тест чинят сразу, а не откладывают.
Частые вопросы
С чего начать, если тестов нет вовсе?
С расчётов и разбора форматов: там ядро не нужно. Первые тесты появляются за час.
Нужно ли поднимать ядро в каждом тесте?
Нет, и лучше не поднимать: это главный источник медленных наборов. Ядро нужно только тестам с базой.
Где брать данные для тестов?
Создавать их в самом тесте и удалять после. Боевые данные для этого не годятся.
Что не стоит покрывать тестами?
Вывод, вёрстку и настройки в интерфейсе. Они меняются чаще, чем ломаются.
Смежное
-
Стенд разработчика - оглавление подтемы
-
Стенд из копии боевого: подъём, обезличивание, отрезанные связи - где эти тесты и запускают
-
Отладчик на стенде: подключение, точки останова, обмен и cron - соседний инструмент разбора
-
Проверки перед выкладкой: синтаксис, стандарт, тесты, миграции - где эти тесты запускаются автоматически
-
Тестирование и выкладка - устройство темы целиком
-
Выкладка на боевой: порядок, структура, откат - куда встраивают прогон тестов
-
PHPUnit и модульное тестирование - устройство темы целиком
-
Архитектура проекта - что где лежит в проекте
-
Тестовые данные для стенда: генерация, пометка, чистка - данные, на которых гоняют проверки