Skip to content
...

Пропуск тестов ​

Плагин предоставляет атрибут #[Skip]#[Skip(string $reason = '')]Помечает тест, класс тестов или тестовую функцию как пропущенные, не запуская их., который помечает тест пропущенным. Тест попадает в отчёт со статусом Status::Skipped\Testo\Core\Value\Status::Skipped и учитывается в итогах, а необязательная причина объясняет, почему он пропущен. Пропускайте тест, когда запускать его пока нельзя, а удалять рано: он воспроизводит ещё не починенный баг, сломан незавершённым рефакторингом или написан раньше фичи, которую проверяет.

Класс плагина: SkipPlugin\Testo\Skip\SkipPlugin. Входит в SuitePlugins\Testo\Application\Config\Plugin\SuitePlugins по умолчанию.

#[Skip] ​

Помечает тест, класс тестов или тестовую функцию как пропущенные, не запуская их.

#[Skip(string $reason = '')]

Можно повесить на метод, свободную функцию или класс — на классе пропускаются все тесты тест-кейса. Атрибут наследуется от родительских классов, трейтов и переопределённых методов. Если #[Skip] стоит и на методе, и на классе, действует атрибут метода, и его причина заменяет причину класса. Это верно и для пустой причины: если на методе стоит #[Skip] без аргумента, тест пропускается без причины, а причина класса не подставляется. Повесить атрибут на один элемент дважды нельзя.

Атрибут действует только на обычные тесты: на не-тестовом методе он ничего не делает, а #[Bench]#[Bench(array $callables, array $arguments = [], int $warmup = 1, int $calls = 1_000, int $iterations = 10)]Объявляет бенчмарк для сравнения производительности метода с альтернативными реализациями. и #[TestInline]#[TestInline(array $arguments, mixed $result = null)]Объявляет встроенный тест на методе или функции. выполняются как обычно. По смыслу близок к @Disabled в JUnit и #[ignore] в Rust.

Параметры:

$reason
Почему тест пропущен. По умолчанию причины нет. Заданная причина дописывается в сообщение результата.

Примеры:

Пропустить один тест:

php
use Testo\Skip;
use Testo\Test;

final class OrderTest
{
    #[Test]
    #[Skip('broken by the pricing rework')]
    public function calculatesTotal(): void
    {
        // никогда не выполняется — в отчёте Skipped с причиной выше
    }

    #[Test]
    public function createsOrder(): void { /* выполняется как обычно */ }
}

На классе — пропускаются все тесты тест-кейса, а метод может указать свою причину:

php
#[Skip('the billing sandbox is down')]
final class BillingTest
{
    #[Test]
    public function chargesCard(): void { /* ... */ }

    #[Test]
    #[Skip('flaky since the gateway upgrade')] // эта причина заменяет причину класса
    public function refundsCard(): void { /* ... */ }
}

Что не запускается ​

Решение о пропуске принимается ещё до старта теста: тест сразу получает статус Status::Skipped\Testo\Core\Value\Status::Skipped, и на этом всё. Поэтому ничего из того, что обычно готовит, оборачивает или повторяет тело теста, не срабатывает:

php
final class OrderTest
{
    #[BeforeTest]
    public function startTransaction(): void
    {
        // для calculatesTotal() не вызывается — готовить нечего
    }

    #[Test]
    #[Skip('broken by the pricing rework')]
    public function calculatesTotal(): void { /* ... */ }

    #[Test]
    public function createsOrder(): void
    {
        // для этого теста startTransaction() выполняется как обычно
    }
}

С хуками уровня класса всё иначе: они привязаны к тест-кейсу, а не к отдельному тесту. #[BeforeClass]#[BeforeClass(int $priority = 0)]Выполняет метод один раз перед всеми тестами в классе. Подходит для дорогой инициализации. и #[AfterClass]#[AfterClass(int $priority = 0)]Выполняет метод один раз после всех тестов в классе. Подходит для очистки ресурсов. выполняются, если в тест-кейсе остался хотя бы один непропущенный тест. Если же пропущены все тесты, эти хуки не вызываются, а экземпляр класса даже не создаётся.

Пропуск в отчётах ​

В результат теста попадает сообщение из полного имени теста — Класс::метод или полное имя функции для функционального теста — и маркера is skipped via #[Skip]; если указана причина, она дописывается в конец:

Tests\Unit\OrderTest::calculatesTotal is skipped via #[Skip] ==> broken by the pricing rework
  • Отчёты JUnit (--log-junit), TeamCity (--teamcity) и HTML показывают это сообщение.
  • Терминал печатает строку пропущенного теста без этого сообщения.
  • Компактный отчёт --json учитывает тест в итогах.

Прогон, в котором пропущены все тесты, считается успешным: Status::Skipped\Testo\Core\Value\Status::Skipped не относится ни к падениям, ни к ошибкам.

Пропуск во время выполнения ​

Иногда решение о пропуске нельзя принять заранее: тест должен сначала осмотреться и пропустить себя по тому, что обнаружит — нет расширения, недоступен сервис, фикстура оказалась пустой. Для этого бросьте SkipTest\Testo\Core\Exception\SkipTest из тела теста. Тест попадёт в отчёт со статусом Status::Skipped\Testo\Core\Value\Status::Skipped и сообщением исключения.

php
use Testo\Core\Exception\SkipTest;

#[Test]
public function requiresPdoMysql(): void
{
    if (!\extension_loaded('pdo_mysql')) {
        throw new SkipTest('pdo_mysql required');
    }

    // ...
}

Оба механизма приводят к одному статусу, но разными путями, и это стоит помнить. Исключение бросается, когда тест уже выполняется: #[BeforeTest]#[BeforeTest(int $priority = 0)]Выполняет метод перед каждым тестом в классе. отработал, аргументы подготовлены (провайдером данных, если он есть), а класс создан, если методу нужен экземпляр. #[Skip]#[Skip(string $reason = '')]Помечает тест, класс тестов или тестовую функцию как пропущенные, не запуская их. объявляется заранее и до всего этого просто не доходит. Отличить их в отчёте просто: маркер is skipped via #[Skip] ставит только атрибут.

Бросайте SkipTest\Testo\Core\Exception\SkipTest только из тела теста. Если бросить его из интерцептора, оно покинет пайплайн, и тест получит статус Status::Aborted\Testo\Core\Value\Status::Aborted, а не Status::Skipped\Testo\Core\Value\Status::Skipped.

Skip, SkipTest или фильтр по группе ​

Все три не дают тесту выполниться, но различаются тем, когда принимается решение и остаётся ли тест в отчёте:

ИнструментГде принимается решениеВ отчёте
#[Skip('…')]в коде, до запускаStatus::Skipped\Testo\Core\Value\Status::Skipped, с причиной
throw new SkipTest('…')внутри теста, во время выполненияStatus::Skipped\Testo\Core\Value\Status::Skipped, с сообщением
#[Group]#[Group(string ...$names)]Помечает класс, метод или функцию одной или несколькими группами для выборочной фильтрации. + --group=!slowпри запуске раннеране отображается