Skip to content

Быстрый старт

Требования

  • PHP 8.3+
  • ext-mbstring
  • ext-random
  • testo/testo ^0.10.25 || ^1.0

Установка

bash
composer require --dev rasuvaeff/property-testing

Регистрация плагина не требуется: атрибут #[Property] саморегистрируется в Testo через механизм обнаружения интерцепторов фреймворка.

Использование

Пометьте тестовый метод атрибутом #[Property] и укажите метод-генератор, сопоставляющий имя каждого параметра с фабрикой Gen. Раннер генерирует случайные аргументы, прогоняет свойство runs раз, а при первом падении shrink'ает контрпример до минимального.

php
use Rasuvaeff\PropertyTesting\Assume;
use Rasuvaeff\PropertyTesting\Gen;
use Rasuvaeff\PropertyTesting\Property;
use Testo\Assert;
use Testo\Test;

#[Test]
final class RetryPolicyPropertyTest
{
    #[Property(runs: 500, generators: 'delayGenerators')]
    public function delayNeverExceedsCap(int $maxAttempts, int $baseSeconds, int $cap, int $attempts): void
    {
        Assume::that($cap >= $baseSeconds);

        $policy = WebhookRetryPolicy::exponential($maxAttempts, $baseSeconds, $cap);

        Assert::true($policy->nextDelaySeconds($attempts) <= $cap);
    }

    /** @return array<string, \Rasuvaeff\PropertyTesting\ArbitraryInterface> */
    public static function delayGenerators(): array
    {
        return [
            'maxAttempts' => Gen::intBetween(1, 50),
            'baseSeconds' => Gen::intBetween(1, 300),
            'cap' => Gen::intBetween(1, 86400),
            'attempts' => Gen::intBetween(1, 100),
        ];
    }
}

При падении контрпример попадает в вывод теста:

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: показывает diff исходного и shrunk-контрпримера: аргументы, которые shrinker не тронул (здесь cap), опущены, поэтому входы, реально приводящие к падению, видны сразу. trial(s) считает каждого кандидата, которого shrinker прогнал (принятого и отвергнутого); shrink step(s) — только принятые.

Чтобы воспроизвести точный прогон, передайте сообщённый seed обратно в атрибут:

php
#[Property(runs: 500, seed: 7382910, generators: 'delayGenerators')]