Skip to content
...
Блог
Группировка тестов: атрибут #[Group]

Группировка тестов через #[Group]

На прошлой неделе я писал новый компонент для Cycle ORM — cycle/transaction. Тесты к нему я, разумеется, писал на Testo — и сразу захотел воспроизвести привычный по Cycle подход: гонять один и тот же набор тестов по всем поддерживаемым базам данных. Тут-то и выяснилось, что одной нужной детали в Testo пока нет.

Как принято писать тесты в Cycle

Тесты Cycle написаны на PHPUnit. Для тестов, которые работают с реальными базами данных, там сложилась удобная практика:

  • Пишется абстрактный класс с тестами;

  • Затем под каждый драйвер наследуются финальные классы, которые подключают конкретный драйвер.

  • На финальных классах проставляются группы:

    php
    /**
     * @group driver
     * @group driver-mysql
     */

    Здесь driver означает, что тест работает с базой напрямую, а driver-mysql уже уточняет конкретный драйвер. Удобство очевидно: можно запустить тесты только на SQLite или на любом другом выбранном драйвере. Ровно так они и вызываются в CI — отдельным прогоном на каждую базу данных.

Группы в Testo

В Testo группировки тестов ещё не было. Так что пришло время это добавить. На всё про всё ушло несколько часов вместе с проверкой гипотез и финальной полировкой: функционал прекрасно вписался в плагин Filter.

Ещё на старте я заметил одну деталь: группу driver в моих тестах можно вынести в родительский класс, а не дублировать в каждом потомке. Поэтому наследование групп я добавил сразу.

Группы здесь — это строковые метки, которые вы навешиваете атрибутом #[Group]#[Group(string ...$names)]Помечает класс, метод или функцию одной или несколькими группами для выборочной фильтрации.. Тот же сценарий с абстрактным классом и драйверами теперь выглядит так:

php
#[Group('driver')]
abstract class TransactionTestCase
{
    public function commitsTransaction(): void { /* ... */ }
}

#[Test]
#[Group('driver-mysql')]
final class MySqlTransactionTest extends TransactionTestCase {}

#[Test]
#[Group('driver-sqlite')]
final class SqliteTransactionTest extends TransactionTestCase {}

Выбор групп при запуске задаётся флагом --group:

bash
# Только тесты на SQLite
testo run --group=driver-sqlite

# Все тесты, работающие с базами напрямую
testo run --group=driver

# Всё, кроме медленных
testo run --group=!slow

Неожиданный финал

Честно говоря, я счёл группировку тестов рядовой фичей и не придал ей особого значения, поэтому не стал писать отдельный пост. Но сегодня пошёл почитать фидбек с запуска беты, и наткнулся на то, что наследование групп просили ещё в PHPUnit с 2019 года. И не получили:

I am sorry to say this, but me this does not sound useful. Inherit groups from parent classes #3935

Забавно: именно эта фича пригодилась мне при первом же использовании атрибута #[Group]#[Group(string ...$names)]Помечает класс, метод или функцию одной или несколькими группами для выборочной фильтрации..


И вот я здесь, чтобы напомнить простую вещь: Testo ориентирован на потребности разработчика.

Если существующий инструмент не решает проблемы сообщества, появление нового — лишь вопрос времени. Так Testo и появился.

Несите свои идеи и потребности в Testo — там у них все шансы быть реализованными. Даже если вы не используете Testo, имейте в виду: фичи из Testo постепенно перетекают и в PHPUnit, просто с опозданием.