Писать тесты — скучно? Только до первого бага в продакшене. С PHPUnit и Yii2 вы можете спать спокойно, зная, что ваш код проверен. В этой статье разберём, как настроить тесты в Yii2, писать их быстро и получать удовольствие.

Digital-студия WNDER

Зачем вообще тестировать Yii2-приложение

Представьте: вы добавили новую фичу, всё работает. Но через неделю выясняется, что сломалась старая функция. Знакомо? Тесты — это ваша страховка. Они автоматически проверяют, что код делает то, что должен. В Yii2 есть встроенная поддержка PHPUnit, так что грех не пользоваться.

К тому же тесты помогают документировать код. Глядя на тест, сразу понятно, как должен вести себя метод. И рефакторить становится не страшно.

Установка и настройка PHPUnit в Yii2

Стандартный шаблон Yii2 (yii2-app-basic) уже включает PHPUnit в dev-зависимости. Если у вас advanced-шаблон, проверьте composer.json. Для установки достаточно выполнить:

composer require --dev phpunit/phpunit

Затем создайте папку tests в корне проекта. Внутри — структуру: unit, functional, acceptance. Для юнит-тестов (проверка отдельных классов) хватит unit.

Настройте автозагрузку. В composer.json добавьте:

"autoload-dev": {
    "psr-4": {
        "tests\\": "tests/"
    }
}

И выполните composer dump-autoload. Теперь можно писать тесты.

Пишем первый юнит-тест

Юнит-тесты проверяют один класс или метод в изоляции. Допустим, у нас есть модель User с методом getFullName(). Создадим тест в tests/unit/models/UserTest.php:

<?php
namespace tests\unit\models;

use app\models\User;
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function testGetFullName()
    {
        $user = new User();
        $user->first_name = 'Иван';
        $user->last_name = 'Петров';
        $this->assertEquals('Иван Петров', $user->getFullName());
    }
}

Запускаем: ./vendor/bin/phpunit tests/unit/models/UserTest.php. Если всё зелёное — отлично!

Правило: каждый тест должен проверять только одну вещь. Не пихайте в один метод десять проверок — потом сами запутаетесь.

Функциональные тесты: проверяем контроллеры

Функциональные тесты эмулируют HTTP-запросы и проверяют ответы. В Yii2 для этого есть класс yii\codeception\fixtures и встроенный TestCase с поддержкой фикстур. Создадим тест для экшена actionIndex контроллера SiteController:

<?php
namespace tests\functional;

use app\controllers\SiteController;
use tests\functional\_base\FunctionalTester;

class SiteControllerTest extends \yii\codeception\TestCase
{
    public function testIndex()
    {
        $this->assertTrue(true); // заглушка
    }
}

На самом деле для функциональных тестов лучше использовать Codeception, который идёт в комплекте с Yii2. Но если хотите чистый PHPUnit, можно тестировать контроллеры через создание экземпляра и вызов экшенов напрямую.

Пример теста для метода контроллера:

public function testActionAbout()
{
    $controller = new SiteController('site', Yii::$app);
    $result = $controller->actionAbout();
    $this->assertIsString($result);
}

Полезные лайфхаки и таблица параметров

Чтобы тесты были быстрыми и надёжными, используйте фикстуры — предустановленные данные. В Yii2 есть yii\test\Fixture. Также не забывайте про изоляцию: каждый тест должен работать независимо.

Вот таблица с основными методами PHPUnit, которые пригодятся:

Метод Что делает
assertEquals($expected, $actual)Проверяет равенство значений
assertTrue($condition)Утверждает, что условие истинно
assertInstanceOf($class, $object)Проверяет, что объект принадлежит классу
expectException($exception)Ожидает исключение
Лайфхак: используйте Data Provider для тестирования разных наборов данных. Это экономит время и делает тесты чище.
/**
 * @dataProvider additionProvider
 */
public function testAdd($a, $b, $expected)
{
    $this->assertEquals($expected, $a + $b);
}

public function additionProvider()
{
    return [
        [0, 0, 0],
        [1, 1, 2],
        [2, 2, 4],
    ];
}

Что в итоге

Тесты в Yii2 с PHPUnit — это не страшно, а полезно. Начните с малого: напишите пару юнит-тестов для моделей. Постепенно добавите функциональные. Главное — регулярность. И помните: хороший тест — это тот, который ловит баг до того, как его увидит пользователь.

Удачи в тестировании! И пусть ваш код всегда будет зелёным.

Студия WNDER