Запуск одного теста, пропуск тестов и другие советы и рекомендации

Источник: «Running a Single Test, Skipping Tests, and Other Tips and Tricks»
Вдохновлённый сообщением создателя Pest Nuno Maduro о методе ->only() в PestPHP, я собрал советы и рекомендации для PHP-разработчиков по эффективной изоляции, пропуску и итерации тестов.

Недавно Nuno Maduro поделился методом ->only(), который можно подключать к тестам с помощью PestPHP. Мне нравятся целевые способы эффективного запуска и повторного выполнения тестов, и этот помощник подтолкнул к идее собрать воедино различные способы фильтрации, пропуска и целевых тестов в PHP. Эта статья ни в коем случае не является исчерпывающей, но надеюсь охватить наиболее важные техники. Я расскажу как о PHPUnit, так и о Pest, где каждый из инструментов применим.

Прежде чем начать, посмотрим на метод only(), предложенный Nuno, который можно прикрепить к отдельным тестам:

it('returns a successful response', function () {
$response = $this->get('/');

$response->assertStatus(200);
})->only();

// Если ->only() используется с несколькими тестами,
// то будут запущены все выбранные тесты.
it('another test', function () {
// ...
})->only();

Использование only() действует как переключатель, который будет нацелен на отдельные тесты, пока вы сосредоточены на написании кода и выполнении тестов для этой функции. Помимо хелпера only(), и PHPUnit, и Pest предоставляют множество способов изолировать, пропускать и итерировать выбранный набор тестов.

Давайте посмотрим!

Фильтрация тестов

Независимо от размера проекта, я предпочитаю запускать небольшие группы тестов изолированно, пока работаю над функционалом. Умение выбирать и фильтровать тесты в PHP — бесценный навык для разработчиков.

У Pest есть много возможностей для фильтрации тестов — включая вышеупомянутый метод ->only() — с помощью комбинации флагов кода или командной строки.

Вот некоторые из флагов, предлагаемых Pest для фильтрации тестов:

pest --dirty
pest --bail # остановка выполнения при первом не пройденном тесте
pest --filter 'returns a successful response'
pest --retry # присваивает более высокий приоритет неудачным тестам
pest --group|--exclude-group # Как PHPUnit, фильтрует по группам тестов.
pest --todo # Список тестов, помеченных как `->todo()`.

Другие флаги и опции для выбора теста описаны в справочнике Pest CLI.

PHPUnit также предоставляет множество способов фильтрации тестов, которые можно использовать в командной строке:

# фильтры для запуска тестов
phpunit --filter test_the_application_returns_a_successful_response
# флаги групп
phpunit --list-groups # список доступных групп
phpunit --group api
phpunit --exclude-group live

PHPUnit предлагает множество других вариантов выбора, которые можно посмотреть, выполнив phpunit --help или посетив документацию по выбору в PHP CLI. Tim MacDonald из Laravel написал статью Tips to Speed Up Your Phpunit Tests на Laravel News — это ресурс, который рекомендую для развития навыков управления тестами.

Pest предлагает выборки, аналогичные PHPUnit, и создаёт несколько отличных DX-хелперов поверх PHPUnit, которые я считаю бесценными.

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

Пропуск тестов помогает при проверке вашего набора тестов, когда знаете, что некоторые тесты либо откровенно сломаны, либо находятся в процессе разработки. Я вижу, что PHPUnit предлагает возможность пропускать тесты, а Pest дополняет её продуктивными инструментами, позволяющими проводить мозговой штурм тестов с помощью PEST Todo и других полезных вещей для пропуска тестов.

Когда я пишу новую функцию, у меня появляется масса идей, пока работаю над начальным функционалом. Идеи приходят быстрее, чем я успеваю писать, поэтому перехожу к файлу тестов и начинаю создавать to-do чек-лист прямо в коде!

it('returns a successful response', function () {
$response = $this->get('/');

$response->assertStatus(200);
});

it('requires a valid email')->todo();
it('detects Gmail addresses with a "+" as a non-unique email.')->todo();
it('requires a strong password')->todo();

Затем можно запустить pest --todo и точно знать, где искать новые функции или тесты, которые я не успел закончить и хочу пересмотреть.

Результат выполнения команды pest --todo
Результат выполнения команды pest --todo

В PHPUnit есть флаги CLI, которые можно использовать для выбора/пропуска тестов, например --exclude-filter или --exclude-group, являющиеся более широкими. Когда необходимо пропустить конкретный тест, можно использовать предоставленный метод markTestIncomplete() в тесте:

public function test_the_application_returns_a_successful_response(): void
{
$this->markTestIncomplete('it requires a valid email');
$response = $this->get('/');

$response->assertStatus(200);
}

Если запустить набор тестов, то появится сообщение, что есть один или несколько незавершённых тестов. Можно вывести более подробный список всех незавершённых тестов с помощью флага --display-incomplete:

Результат выполнения команды phpunit --display-incomplete
Результат выполнения команды phpunit --display-incomplete

Незавершённые тесты — ближайший эквивалент метода todo() в Pest. Хотя можно добиться подобного с помощью markTestAsSkipped(), я бы оставил этот метод для пропуска тестов, которые не должны выполняться на целевой платформе или в данном сценарии.

Запуск тестов для определённых версий PHP или ОС

Если кодовая база поддерживает несколько версий PHP, иногда имеет смысл пропустить определённые тесты для определённого набора версий PHP, операционных систем или расширений. И Pest, и PHPUnit предлагают гибкую поддержку таких потребностей.

В PHPUnit есть атрибут RequiresPhp, который можно использовать для определения версий PHP в тестах, а также различные атрибуты операционной системы:

use PHPUnit\Framework\Attributes\RequiresOperatingSystemFamily;
use PHPUnit\Framework\Attributes\RequiresPhp;

#[RequiresPhp('<=8.0.0')]
#[RequiresOperatingSystemFamily('Windows')]
public function test_the_application_returns_a_successful_response(): void
{
$response = $this->get('/');

$response->assertStatus(200);
}

Примечание: Исторически PHPUnit использовал аннотацию @requires (она устарела) для определения нескольких типов общих предусловий, таких как версия PHP, ОС, функции и т.д.

При запуске вышеприведённого теста он будет пропущен для систем с версией PHP >8.0.0 или ОС, отличными от семейства Windows. Запустив набор тестов с параметром --display-skipped, можно получить подробную информацию о всех пропущенных тестах на основе этих атрибутов:

Результат выполнения команды phpunit --display-skipped
Результат выполнения команды phpunit --display-skipped

В рамках документации Pest's Skipping Tests можно использовать следующие методы для пропуска определённых версий PHP, версий ОС и т.д.

it('has home', function () {
//
})->skipOnPhp('>=8.0.0');

it('has home', function () {
//
})->skipOnWindows(); // или skipOnMac() или skipOnLinux() ...

it('has home', function() {
//
})->onlyOnWindows(); // или onlyOnMac() или onlyOnLinux() ...

Запуск отдельного теста из редактора

И последнее, о чем стоит упомянуть, это то, что IDE предлагают способы быстрого запуска отдельных тестов, групп тестов, всех тестов в одном файле и т. д. с помощью быстрых командных сочетаний. Расширение Better PHPUnit VS Code Extension поддерживает как PHPUnit, так и Pest, и предоставляет следующие возможности:

PHPStorm предлагает массу удобных способов запуска (и повторного запуска) тестов с помощью ярлыков и иконок пользовательского интерфейса, что позволяет легко запускать тест из тестового файла, не переходя в командную строку:

Запуск теста из PHPStorm
Запуск теста из PHPStorm

Подробнее о настройке ярлыков и инструментов тестирования для PHPUnit и Pest написано в документации PhpStorm.

Заслуживает упоминания плагин sublime-phpunit, позволяющий запускать отдельные юнит-тесты и файлы непосредственно из Sublime.

Какие ещё IDE и инструменты текстовых редакторов вы используете для автоматизации выполнения тестов? Расскажите нам!

Дополнительные материалы

Предыдущая Статья

Понимание SQL оператора ORDER BY

Следующая Статья

Две мощные техники: CSS Reset и normalize.css