Что такое property-testing
Большинство PHP-тестов — пример-based: берём вход, проверяем выход.
public function reversingAOneTwoThree(): void
{
Assert::same([3, 2, 1], array_reverse([1, 2, 3]));
}Это доказывает, что функция работает правильно для [1, 2, 3]. Но ничего не говорит про [], [0], список из 10 000 элементов или список с -0.0. Каждый дополнительный кейс, который вы придумали — ещё один тест, который нужно написать, а те, что вы не придумали — как раз то место, где прячутся баги.
Property-based testing меняет направление. Вместо конкретного входа вы формулируете закон, который должен выполняться для любого входа из некоторого домена:
#[Property(runs: 200)]
public function reversingTwiceRestoresTheList(array $xs): void
{
Assert::same(array_reverse(array_reverse($xs)), $xs);
}Раннер генерирует 200 случайных массивов — пустые, огромные, с повторами, с отрицательными числами, с PHP_INT_MAX — и проверяет закон на каждом. Если один из них падает, раннер не просто сообщает про этот случайный вход: он shrink'ает его, ищет в дереве меньших кандидатов простейший вход, который всё ещё ломает закон, и сообщает уже его.
Property falsified after 246 successful run(s); seed=7382910
Original: maxAttempts=17, baseSeconds=91, cap=847, attempts=23
Shrunk: maxAttempts=1, baseSeconds=848, cap=847, attempts=1 (12 shrink step(s), 41 trial(s))
Changed: maxAttempts=17 -> 1, baseSeconds=91 -> 848, attempts=23 -> 1В этом вся идея: генерировать широко, потом минимизировать точно. Строка Changed: выше — и есть выигрыш: из четырёх сгенерированных аргументов на падение реально влияют только три, и вы знаете это без пошагового дебага.
Что добавляет этот пакет
- Атрибут
#[Property], который подключается прямо к обычному Testo тест-кейсу — без отдельного раннера, без нового тест-фреймворка. - Десятки встроенных генераторов (
Gen::int(),Gen::string(),Gen::arrayOf(), …) плюс инструменты для своих — см. Генераторы. - Integrated shrinking: каждый генератор уже знает, как минимизировать собственные значения — см. Shrinking.
- Путь дальше одиночных входов — к случайным последовательностям операций над stateful-системой — см. State machine тестирование.
Дальше
Быстрый старт устанавливает пакет и проводит через написание первого property. Концепции — короткий глоссарий терминов, используемых по всему сайту (property, arbitrary, shrinking, counterexample, seed), если хочется сначала прочитать определения.