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

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

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

Начать курс

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

PHPUnit — это фреймворк для модульного тестирования (unit testing) на языке PHP. Он является частью семейства xUnit и предоставляет разработчикам инструменты для автоматизации проверки работоспособности отдельных компонентов программы (классов, методов, функций).

Зачем нужен PHPUnit?

  • Раннее обнаружение ошибок: Тесты запускаются после каждого изменения кода, позволяя моментально выявить регрессии.
  • Документация кода: Хорошо написанные тесты служат живой документацией, показывающей, как должен работать тот или иной метод.
  • Рефакторинг без страха: Вы можете смело переписывать код, будучи уверенным, что тесты не дадут сломать существующую функциональность.
  • Поддержка TDD (Test-Driven Development): Разработка через тестирование — методология, при которой сначала пишется тест, а затем минимальный код для его прохождения.
  • Интеграция с CI/CD: PHPUnit легко встраивается в пайплайны непрерывной интеграции (GitHub Actions, GitLab CI, Jenkins).

PHPUnit поддерживает моки (mock-объекты), фикстуры (наборы данных для тестов), покрытие кода (code coverage) и множество других продвинутых функций.

Установка PHPUnit

PHPUnit устанавливается через Composer — менеджер зависимостей для PHP. Если у вас ещё нет Composer, установите его с официального сайта getcomposer.org.

Глобальная установка (рекомендуется для CLI)

composer global require phpunit/phpunit

После этого убедитесь, что директория глобальных пакетов Composer добавлена в PATH. Проверьте установку:

phpunit --version

Локальная установка (внутри проекта)

composer require --dev phpunit/phpunit

После этого PHPUnit будет доступен через vendor/bin/phpunit.

Установка конкретной версии

composer require --dev phpunit/phpunit:^10.0

Важно: Версия PHPUnit должна соответствовать версии PHP в вашем проекте. Например, PHPUnit 10 требует PHP 8.1 или выше.

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

Создадим простой класс Calculator.php и напишем для него тесты.

Шаг 1. Создаём класс для тестирования

<?php
// src/Calculator.php

class Calculator
{
    public function add(int $a, int $b): int
    {
        return $a + $b;
    }

    public function subtract(int $a, int $b): int
    {
        return $a - $b;
    }

    public function multiply(int $a, int $b): int
    {
        return $a * $b;
    }

    public function divide(int $a, int $b): float
    {
        if ($b === 0) {
            throw new \InvalidArgumentException("Division by zero");
        }
        return $a / $b;
    }
}

Шаг 2. Создаём тестовый класс

<?php
// tests/CalculatorTest.php

use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase
{
    private Calculator $calculator;

    protected function setUp(): void
    {
        $this->calculator = new Calculator();
    }

    public function testAdd(): void
    {
        $result = $this->calculator->add(2, 3);
        $this->assertEquals(5, $result);
    }

    public function testSubtract(): void
    {
        $result = $this->calculator->subtract(10, 4);
        $this->assertEquals(6, $result);
    }

    public function testMultiply(): void
    {
        $result = $this->calculator->multiply(3, 4);
        $this->assertEquals(12, $result);
    }

    public function testDivide(): void
    {
        $result = $this->calculator->divide(10, 2);
        $this->assertEquals(5.0, $result);
    }

    public function testDivideByZero(): void
    {
        $this->expectException(\InvalidArgumentException::class);
        $this->calculator->divide(10, 0);
    }
}

Шаг 3. Запускаем тесты

vendor/bin/phpunit tests/CalculatorTest.php

Вы должны увидеть зелёный вывод с надписью "OK (5 tests, 5 assertions)".

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

Ниже приведены ключевые методы (assertions), которые вы будете использовать в 90% случаев.

1. assertEquals()

Что делает: Проверяет, что два значения равны (сравнение через оператор ==).

Параметры:

  • mixed $expected — ожидаемое значение
  • mixed $actual — фактическое значение
  • string $message = '' — сообщение при ошибке (опционально)

Пример:

$this->assertEquals(5, 2 + 3);
$this->assertEquals('hello', strtolower('HELLO'));

2. assertSame()

Что делает: Проверяет строгое равенство (сравнение через ===). Различает 0 и false, null и пустую строку.

Параметры: Аналогично assertEquals.

Пример:

$this->assertSame(0, 0); // пройдёт
$this->assertSame(0, false); // не пройдёт, хотя assertEquals пройдёт

3. assertTrue() / assertFalse()

Что делает: Проверяет, что выражение истинно или ложно.

Параметры:

  • bool $condition — проверяемое условие
  • string $message = ''

Пример:

$this->assertTrue(5 > 3);
$this->assertFalse(empty([])); // пустой массив считается empty, но assertFalse пройдёт

4. assertNull() / assertNotNull()

Что делает: Проверяет, является ли значение null или не null.

Параметры:

  • mixed $variable — проверяемая переменная
  • string $message = ''

Пример:

$this->assertNull(null);
$this->assertNotNull('not null');

5. assertCount()

Что делает: Проверяет, что количество элементов в массиве или объекте Countable равно ожидаемому.

Параметры:

  • int $expectedCount — ожидаемое количество
  • Countable|array $haystack — массив или объект
  • string $message = ''

Пример:

$this->assertCount(3, [1, 2, 3]);
$this->assertCount(0, []);

6. assertContains()

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

Параметры:

  • mixed $needle — искомое значение
  • iterable $haystack — массив или строка
  • string $message = ''

Пример:

$this->assertContains(2, [1, 2, 3]);
$this->assertContains('world', 'hello world');

7. assertInstanceOf()

Что делает: Проверяет, что объект является экземпляром указанного класса или интерфейса.

Параметры:

  • string $expected — имя класса
  • object $actual — проверяемый объект
  • string $message = ''

Пример:

$this->assertInstanceOf(Calculator::class, $this->calculator);
$this->assertInstanceOf(Countable::class, new ArrayObject());

8. expectException()

Что делает: Указывает, что следующий код должен выбросить исключение указанного типа.

Параметры:

  • string $exceptionClass — класс ожидаемого исключения

Пример:

$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage('Division by zero');
$this->calculator->divide(10, 0);

9. assertArrayHasKey()

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

Параметры:

  • mixed $key — искомый ключ
  • array $array — массив
  • string $message = ''

Пример:

$this->assertArrayHasKey('name', ['name' => 'John', 'age' => 30]);

10. assertStringContainsString()

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

Параметры:

  • string $needle — искомая подстрока
  • string $haystack — строка для поиска
  • string $message = ''

Пример:

$this->assertStringContainsString('PHP', 'PHPUnit is great');

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

Предположим, у нас есть интернет-магазин. Напишем тесты для класса OrderProcessor, который обрабатывает заказы.

Класс OrderProcessor

<?php
// src/OrderProcessor.php

class OrderProcessor
{
    private array $items = [];
    private float $total = 0.0;
    private bool $paid = false;

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

    public function getTotal(): float
    {
        return $this->total;
    }

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

    public function pay(float $amount): void
    {
        if ($amount < $this->total) {
            throw new \RuntimeException("Insufficient funds");
        }
        $this->paid = true;
    }

    public function isPaid(): bool
    {
        return $this->paid;
    }

    public function getItems(): array
    {
        return $this->items;
    }
}

Тесты для OrderProcessor

<?php
// tests/OrderProcessorTest.php

use PHPUnit\Framework\TestCase;

class OrderProcessorTest extends TestCase
{
    private OrderProcessor $processor;

    protected function setUp(): void
    {
        $this->processor = new OrderProcessor();
    }

    public function testAddItem(): void
    {
        $this->processor->addItem('Laptop', 999.99, 1);
        $this->assertCount(1, $this->processor->getItems());
        $this->assertEquals(999.99, $this->processor->getTotal());
    }

    public function testMultipleItems(): void
    {
        $this->processor->addItem('Mouse', 25.50, 2);
        $this->processor->addItem('Keyboard', 75.00, 1);
        
        $this->assertCount(2, $this->processor->                    

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