Pest для PHP: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Что такое Pest и зачем он нужен?

Pest — это современный, элегантный фреймворк для тестирования на языке PHP, созданный Нуно Мадуро (Nuno Maduro) в 2021 году. В отличие от традиционных решений, таких как PHPUnit, Pest предлагает более лаконичный и выразительный синтаксис, вдохновлённый Jest (JavaScript) и RSpec (Ruby). Если PHPUnit — это "швейцарский нож" для тестирования, то Pest — это "скальпель", который позволяет писать тесты быстрее, чище и с меньшим количеством шаблонного кода.

Основная цель Pest — сделать процесс написания тестов максимально приятным и интуитивно понятным. Вместо классов и методов с длинными именами, вы используете замыкания (closures) и цепочки вызовов (fluent interface). Это особенно полезно для проектов, где важна скорость разработки и читаемость кода, например, в стартапах, API-сервисах или при работе в команде, где тесты пишут не только QA-инженеры, но и разработчики.

Ключевые преимущества Pest перед PHPUnit:

  • Лаконичность: Меньше кода для написания одного и того же теста.
  • Читаемость: Тесты выглядят как естественный язык (например, expect($result)->toBeTrue()).
  • Встроенные функции: beforeEach(), afterEach(), todo() и другие.
  • Архитектура: Не требует обязательного наследования от TestCase.
  • Экосистема: Плагины для Laravel, Livewire, Mockery и других популярных инструментов.

Установка Pest

Pest устанавливается через Composer — стандартный менеджер пакетов для PHP. Убедитесь, что у вас установлен PHP версии 8.0 или выше.

Создайте новый проект или перейдите в корневую директорию существующего проекта:

mkdir my-pest-project
cd my-pest-project
composer init --yes

Установите Pest как зависимость для разработки (dev):

composer require pestphp/pest --dev

После установки инициализируйте Pest в вашем проекте:

./vendor/bin/pest --init

Эта команда создаст базовую структуру:

  • tests/ — директория для тестов.
  • tests/Pest.php — файл с глобальными настройками (например, uses()).
  • phpunit.xml — конфигурационный файл (Pest работает поверх PHPUnit).

Теперь вы можете запустить тесты:

./vendor/bin/pest

Если вы используете Laravel, установите дополнительный пакет для лучшей интеграции:

composer require pestphp/pest-plugin-laravel --dev

Быстрый старт с примером кода

Создайте файл tests/ExampleTest.php:

<?php

test('basic assertion', function () {
    $result = 1 + 1;
    expect($result)->toBe(2);
});

Запустите тесты:

./vendor/bin/pest

Вы увидите зелёный вывод с сообщением PASS Tests\ExampleTest. Обратите внимание: мы не использовали классы, методы с аннотациями или наследование. Просто функция test() и замыкание. Это и есть "современное тестирование".

Альтернативный синтаксис с использованием ключевого слова it (более читаемый для описания поведения):

it('performs basic addition', function () {
    $sum = 2 + 3;
    expect($sum)->toEqual(5);
});

Основные методы и функции Pest

Ниже приведены 10 ключевых методов и функций Pest с подробным описанием и примерами.

1. test() — определение теста

Что делает: Создаёт новый тест. Это основная функция для определения тестового сценария.

Параметры:

  • string $description — описание теста (выводится в консоли).
  • callable $closure — замыкание, содержащее логику теста.

Пример:

test('string length is correct', function () {
    $string = 'Hello, Pest!';
    expect(strlen($string))->toBe(12);
});

2. it() — альтернатива test()

Что делает: Работает аналогично test(), но добавляет слово "it" перед описанием, что делает тесты более читаемыми (например, "it returns true when condition is met").

Параметры: Те же, что и у test().

Пример:

it('returns true for valid email', function () {
    $validator = new EmailValidator();
    expect($validator->validate('user@example.com'))->toBeTrue();
});

3. expect() — создание ожидания (assertion)

Что делает: Создаёт объект ожидания, к которому можно применить цепочку методов для проверки значений. Это замена традиционным assertXxx() методам PHPUnit.

Параметры:

  • mixed $value — значение, которое нужно проверить.

Пример:

test('expect example', function () {
    $array = [1, 2, 3];
    expect($array)->toHaveCount(3);
    expect($array[0])->toBeInt();
});

4. toBe() — строгое сравнение (===)

Что делает: Проверяет, что значение идентично ожидаемому (строгое сравнение с учётом типа).

Параметры:

  • mixed $expected — ожидаемое значение.

Пример:

test('strict comparison', function () {
    $value = 42;
    expect($value)->toBe(42);   // true
    expect($value)->toBe('42'); // false (разные типы)
});

5. toEqual() — нестрогое сравнение (==)

Что делает: Проверяет, что значение равно ожидаемому с приведением типов.

Параметры:

  • mixed $expected — ожидаемое значение.

Пример:

test('loose comparison', function () {
    expect(42)->toEqual('42'); // true, так как 42 == '42'
});

6. toThrow() — проверка исключений

Что делает: Проверяет, что замыкание выбрасывает исключение. Можно указать класс исключения и/или сообщение.

Параметры:

  • string $exceptionClass (опционально) — класс ожидаемого исключения.
  • string $exceptionMessage (опционально) — текст сообщения исключения.

Пример:

test('exception throwing', function () {
    expect(function () {
        throw new \InvalidArgumentException('Invalid data');
    })->toThrow(\InvalidArgumentException::class, 'Invalid data');
});

7. beforeEach() — подготовка перед каждым тестом

Что делает: Выполняет заданное замыкание перед каждым тестом в файле. Идеально для инициализации общих объектов (например, подключение к БД, создание моков).

Параметры:

  • callable $closure — замыкание с подготовительной логикой.

Пример:

beforeEach(function () {
    $this->user = new User(['name' => 'John']);
});

test('user name is John', function () {
    expect($this->user->name)->toBe('John');
});

8. afterEach() — очистка после каждого теста

Что делает: Выполняет замыкание после каждого теста. Полезно для сброса состояния (удаление временных файлов, закрытие соединений).

Параметры:

  • callable $closure — замыкание с логикой очистки.

Пример:

afterEach(function () {
    Mockery::close(); // очистка моков Mockery
});

9. todo() — пометка теста как "запланированного"

Что делает: Создаёт тест, который будет отмечен как "TODO" в отчёте. Не содержит логики и не выполняется. Помогает планировать тесты.

Параметры:

  • string $description — описание того, что нужно протестировать.

Пример:

todo('test user registration with invalid email');
todo('test password reset flow');
skip() — пропуск теста по условию

Что делает: Пропускает выполнение теста, если условие истинно. Полезно для тестов, которые зависят от окружения (например, версия PHP, наличие расширения).

Параметры:

  • bool|callable $condition — условие пропуска.
  • string $message (опционально) — причина пропуска.

Пример:

test('feature requires PHP 8.1', function () {
    // тест, использующий фичи PHP 8.1
})->skip(PHP_VERSION_ID < 80100, 'Требуется PHP 8.1 или выше');

Реальный практический пример использования

Предположим, у нас есть простой сервис для управления корзиной покупок (CartService). Мы хотим протестировать добавление товаров, подсчёт суммы и очистку корзины.

Структура проекта:

src/
  CartService.php
tests/
  CartServiceTest.php
  Pest.php

Класс CartService:

<?php

class CartService
{
    private array $items = [];

    public function addItem(string $name, float $price, int $quantity = 1): void
    {
        $this->items[] = ['name' => $name, 'price' => $price, 'quantity' => $quantity];
    }

    public function getTotal(): float
    {
        return array_sum(array_map(fn($item) => $item['price'] * $item['quantity'], $this->items));
    }

    public function clear(): void
    {
        $this->items = [];
    }

    public function count(): int
    {
        return count($this->items);
    }
}

Тест CartServiceTest.php:

<?php

use function Pest\Faker\fake; // если установлен плагин faker

beforeEach(function () {
    $this->cart = new CartService();
});

test('can add items to cart', function () {
    $this->cart->addItem('Laptop', 1500.00, 1);
    $this->cart->addItem('Mouse', 25.50, 2);

    expect($this->cart->count())->toBe(2);
});

test('calculates total correctly', function () {
    $this->cart->addItem('Laptop', 1500.00, 1);
    $this->cart->addItem('Mouse', 25.50, 2);

    $expectedTotal = 1500.00 + (25                    

Рекомендаций