Skip to content

Основы PHP: Юнит-тестирование

Юнит-тестирование является важной практикой в разработке программного обеспечения, которая помогает:

  • Обнаруживать ошибки на ранних стадиях: Легче и дешевле исправить ошибку, найденную на этапе разработки, чем в уже развернутом приложении.
  • Улучшать качество кода: Написание тестов заставляет разработчиков писать более чистый и структурированный код, который легче тестировать.
  • Облегчать рефакторинг: При изменении кода наличие юнит-тестов позволяет быстро убедиться, что изменения не сломали существующую функциональность.
  • Служить документацией: Тесты показывают, как должен работать тот или иной модуль кода.

PHPUnit

Наиболее популярным фреймворком для юнит-тестирования в PHP является PHPUnit. Это мощный и гибкий фреймворк, предоставляющий множество инструментов для написания и запуска тестов.

Установка PHPUnit

Рекомендуется устанавливать PHPUnit как зависимость вашего проекта с помощью Composer:

bash
composer require --dev phpunit/phpunit

Флаг --dev указывает, что PHPUnit является зависимостью для разработки и не будет включен в production-версию вашего приложения.

После установки PHPUnit будет доступен в директории vendor/bin/phpunit.

Написание юнит-тестов

Юнит-тесты обычно пишутся в отдельных файлах, которые находятся в специальной директории (например, tests/). Имена файлов тестов обычно имеют суффикс Test.php (например, CalculatorTest.php).

Каждый файл теста представляет собой класс, который наследуется от класса PHPUnit\Framework\TestCase. Внутри этого класса определяются методы тестов, имена которых обычно начинаются со слова test (например, testAddition()).

Вот пример простого класса для тестирования:

php
<?php
// src/Calculator.php
class Calculator {
    public function add($a, $b) {
        return $a + $b;
    }

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

И соответствующий файл теста:

php
<?php
// tests/CalculatorTest.php
use PHPUnit\Framework\TestCase;

class CalculatorTest extends TestCase {
    public function testAddition() {
        $calculator = new Calculator();
        $result = $calculator->add(2, 3);
        $this->assertEquals(5, $result);
    }

    public function testSubtraction() {
        $calculator = new Calculator();
        $result = $calculator->subtract(5, 2);
        $this->assertEquals(3, $result);
    }
}

Разберем этот пример:

  • use PHPUnit\Framework\TestCase;: Импортируем класс TestCase, от которого должен наследоваться наш класс теста.
  • class CalculatorTest extends TestCase: Объявляем класс теста CalculatorTest, который тестирует класс Calculator.
  • public function testAddition() и public function testSubtraction(): Это методы тестов. Имена методов, начинающиеся с test, автоматически распознаются PHPUnit как тестовые методы.
  • $calculator = new Calculator();: Создаем экземпляр класса, который мы хотим протестировать.
  • $result = $calculator->add(2, 3);: Вызываем метод тестируемого класса и получаем результат.
  • $this->assertEquals(5, $result);: Это утверждение (assertion). Утверждения — это методы, предоставляемые TestCase, которые проверяют, соответствует ли ожидаемый результат фактическому результату. В данном случае мы утверждаем, что результат сложения 2 и 3 должен быть равен 5.

PHPUnit предоставляет множество различных утверждений для проверки различных условий (равенство, неравенство, истинность, ложность, исключения и т.д.). Некоторые из наиболее часто используемых утверждений:

  • assertEquals($expected, $actual): Проверяет, что два значения равны.
  • assertSame($expected, $actual): Проверяет, что два значения равны и имеют один и тот же тип.
  • assertNotEquals($expected, $actual): Проверяет, что два значения не равны.
  • assertNotSame($expected, $actual): Проверяет, что два значения не равны или имеют разные типы.
  • assertTrue($condition): Проверяет, что условие истинно.
  • assertFalse($condition): Проверяет, что условие ложно.
  • assertNull($actual): Проверяет, что значение равно null.
  • assertNotNull($actual): Проверяет, что значение не равно null.
  • assertEmpty($actual): Проверяет, что переменная пуста (например, пустая строка, пустой массив).
  • assertNotEmpty($actual): Проверяет, что переменная не пуста.
  • assertGreaterThan($expected, $actual): Проверяет, что $actual больше, чем $expected.
  • assertLessThan($expected, $actual): Проверяет, что $actual меньше, чем $expected.
  • assertStringContainsString($needle, $haystack): Проверяет, что строка $haystack содержит подстроку $needle.
  • assertArrayHasKey($key, $array): Проверяет, что массив $array имеет ключ $key.
  • assertCount($expectedCount, $arrayOrTraversable): Проверяет количество элементов в массиве или объекте, реализующем интерфейс Countable или Traversable.
  • expectException($exceptionClassName): Ожидает, что тестируемый код выбросит исключение указанного класса.

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

Запуск юнит-тестов

Чтобы запустить тесты, перейдите в корневую директорию вашего проекта в командной строке и выполните команду:

bash
./vendor/bin/phpunit tests

Здесь tests — это директория, в которой находятся ваши файлы тестов. PHPUnit автоматически найдет и выполнит все классы, которые наследуются от PHPUnit\Framework\TestCase и содержат методы, начинающиеся с test.

Результат выполнения тестов будет отображен в консоли, показывая, какие тесты прошли (OK) и какие не прошли (FAIL или ERROR), а также подробную информацию об ошибках.

Организация тестов

Для больших проектов рекомендуется создавать более сложную структуру директорий для тестов, отражающую структуру вашего кода. Вы также можете использовать конфигурационный файл phpunit.xml в корне вашего проекта для настройки параметров запуска тестов, указания директорий с тестами, фильтрации тестов и многого другого.

Пример файла phpunit.xml:

xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="[http://www.w3.org/2001/XMLSchema-instance](http://www.w3.org/2001/XMLSchema-instance)"
         xsi:noNamespaceSchemaLocation="./vendor/phpunit/phpunit/phpunit.xsd"
         bootstrap="vendor/autoload.php"
         colors="true"
         verbose="true">
    <testsuites>
        <testsuite name="Application Tests">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
    </testsuites>
    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./src</directory>
        </include>
        <report>
            <clover outputFile="./build/coverage/clover.xml"/>
        </report>
    </coverage>
    <php>
        <ini name="error_reporting" value="-1"/>
        <ini name="memory_limit" value="256M"/>
    </php>
</phpunit>

С таким конфигурационным файлом вы можете просто запустить PHPUnit из корневой директории:

bash
./vendor/bin/phpunit

Лучшие практики юнит-тестирования

  • Пишите тесты для всего важного кода: Стремитесь к высокому покрытию кода тестами.
  • Тестируйте граничные случаи (edge cases): Проверяйте поведение кода при необычных входных данных или условиях.
  • Каждый тест должен тестировать только одну логическую единицу: Это делает тесты более понятными и изолированными.
  • Тесты должны быть быстрыми: Юнит-тесты должны выполняться быстро, чтобы не замедлять процесс разработки.
  • Тесты должны быть независимыми: Результат одного теста не должен зависеть от результата другого.
  • Используйте фикстуры (fixtures) для настройки окружения: Фикстуры позволяют подготовить данные или объекты, необходимые для выполнения тестов. PHPUnit предоставляет различные способы создания фикстур (setUp(), tearDown(), setUpBeforeClass(), tearDownAfterClass()).
  • Следуйте принципу AAA (Arrange, Act, Assert):
    • Arrange: Подготовьте необходимые данные и окружение для теста.
    • Act: Выполните тестируемое действие (например, вызовите метод).
    • Assert: Проверьте результат с помощью утверждений.
  • Пишите тесты до написания кода (TDD - Test-Driven Development): Хотя это не всегда возможно, написание тестов перед кодом помогает лучше понять требования и спроектировать более тестируемый код.

Юнит-тестирование является неотъемлемой частью процесса разработки качественного программного обеспечения на PHP. Использование PHPUnit позволяет писать эффективные и надежные тесты, которые помогут вам поддерживать и развивать ваш код с уверенностью.