Разработка без тестов — это как езда на автомобиле без ремня безопасности: вроде едешь, но в любой момент может прилететь. Особенно когда проект растёт, а сроки поджимают. Я сам долго откладывал тесты, думая, что это слишком сложно и скучно. Но когда попробовал Codeception в связке с Yii2, понял: это не больно, а даже удобно. В этой статье расскажу, как подружить эти два инструмента и сделать свою жизнь проще.
Ссылка на оригинальную статьюПочему именно Codeception?
На рынке есть много инструментов для тестирования: PHPUnit, Behat, PHPSpec. Но Codeception выделяется тем, что он как швейцарский нож: умеет всё и сразу. Он поддерживает три уровня тестов — юнит, функциональные и приёмочные. А ещё он интегрируется с Yii2 буквально из коробки.
Представьте, что вы строите дом. Юнит-тесты — это проверка каждого кирпича отдельно. Функциональные — проверка, что стены стоят ровно. А приёмочные — что в доме можно жить. Codeception позволяет проверить все три уровня, не переключаясь между разными инструментами.
Плюс у Codeception очень понятный синтаксис. Даже если вы никогда не писали тесты, разберётесь за вечер. Например, чтобы проверить, что страница открывается, нужно всего несколько строк.
Настройка Codeception в Yii2
Сначала установим Codeception через Composer. Если вы ещё не знакомы с Composer — это менеджер пакетов для PHP, как pip для Python. В корне проекта выполните:
composer require --dev codeception/codeception yii2-codeception
После установки нужно инициализировать Codeception. Для этого в папке tests выполните команду:
vendor/bin/codecept init
Эта команда создаст базовую структуру: папки unit, functional, acceptance, а также файлы конфигурации. В Yii2 обычно уже есть папка tests с базовыми настройками, так что можно просто подправить конфиг.
Теперь настроим подключение к базе данных. В файле tests/codeception.yml укажите параметры подключения, чтобы тесты использовали отдельную базу (например, с суффиксом _test). Это важно, чтобы не засорять рабочую базу.
modules:
config:
Db:
dsn: 'mysql:host=localhost;dbname=myapp_test'
user: 'root'
password: ''
dump: 'tests/_data/dump.sql'
populate: true
cleanup: true
После этого можно запустить тесты командой vendor/bin/codecept run. Если всё настроено правильно, вы увидите зелёные строки — значит, тесты работают.
Пишем юнит-тесты для моделей
Юнит-тесты — это самый простой уровень. Они проверяют отдельные методы классов. Например, у вас есть модель User с методом getFullName(). Напишем тест, который проверяет, что метод правильно склеивает имя и фамилию.
Создайте файл tests/unit/models/UserTest.php:
<?php
namespace tests\unit\models;
use app\models\User;
use Codeception\Test\Unit;
class UserTest extends Unit
{
public function testGetFullName()
{
$user = new User();
$user->first_name = 'Иван';
$user->last_name = 'Петров';
$this->assertEquals('Иван Петров', $user->getFullName());
}
}
Здесь мы создаём объект модели, задаём атрибуты и проверяем, что метод возвращает ожидаемую строку. Если метод работает неправильно, тест упадёт — и вы сразу узнаете, что что-то сломано.
Юнит-тесты особенно полезны для проверки бизнес-логики: расчётов, валидации, обработки данных. Они выполняются быстро, поэтому их можно гонять хоть после каждого изменения.
Функциональные тесты: проверяем работу сайта изнутри
Функциональные тесты имитируют запросы к приложению, но без реального браузера. Они проверяют, что контроллеры, экшены и представления работают правильно. Это как если бы вы отправляли запросы через curl, но с дополнительными проверками.
Например, проверим, что страница входа открывается и показывает форму. Создайте tests/functional/LoginCest.php:
<?php
namespace tests\functional;
use FunctionalTester;
class LoginCest
{
public function testLoginPageWorks(FunctionalTester $I)
{
$I->amOnPage('/site/login');
$I->see('Login', 'h1');
$I->fillField('#login-form-username', 'admin');
$I->fillField('#login-form-password', 'password');
$I->click('Login');
$I->see('Logout');
}
}
Что здесь происходит? Мы открываем страницу /site/login, проверяем, что заголовок содержит слово Login, заполняем поля формы и отправляем её. После отправки ожидаем, что появится кнопка Logout — значит, мы успешно вошли.
Функциональные тесты работают быстрее приёмочных, потому что не используют браузер. Но они всё равно проверяют весь стек: маршрутизацию, контроллеры, модели, представления.
Приёмочные тесты: эмулируем действия пользователя
Приёмочные тесты — это самый близкий к реальности уровень. Они запускают настоящий браузер (через WebDriver) и имитируют клики, ввод текста, переходы по страницам. Это как если бы вы наняли тестировщика, который сидит и щёлкает по сайту.
Для работы приёмочных тестов нужен Selenium Server или ChromeDriver. Но не пугайтесь, настройка несложная. Главное — указать в конфиге адрес сервера.
modules:
config:
WebDriver:
url: 'http://localhost:8080'
browser: chrome
window_size: 1280x1024
Пример приёмочного теста для регистрации:
<?php
namespace tests\acceptance;
use AcceptanceTester;
class RegistrationCest
{
public function testRegistration(AcceptanceTester $I)
{
$I->amOnPage('/site/signup');
$I->fillField('Имя', 'Иван');
$I->fillField('Email', 'ivan@example.com');
$I->fillField('Пароль', 'secret123');
$I->click('Зарегистрироваться');
$I->see('Добро пожаловать');
}
}
Приёмочные тесты помогают поймать проблемы, которые не видны на других уровнях: например, ошибки JavaScript, некорректное отображение вёрстки, проблемы с AJAX-запросами. Но они самые медленные, поэтому их обычно запускают реже.
Практические советы и лайфхаки
Теперь поделюсь тем, что сам набил шишками. Эти советы сэкономят вам кучу времени.
Вот ещё несколько лайфхаков:
- Группируйте тесты по фичам. Например, все тесты для модуля заказов поместите в папку order. Так проще ориентироваться и запускать только нужное.
- Используйте фабрики данных. Вместо ручного создания объектов в каждом тесте, используйте Fixtures или Faker. Это ускоряет написание тестов и делает их чище.
- Пишите тесты сразу после написания кода. Если отложить на потом, забудете, что проверять. Лучше писать тесты параллельно с разработкой.
- Не гонитесь за 100% покрытием. Это миф, что нужно покрыть всё. Сосредоточьтесь на критических путях: регистрация, вход, оформление заказа, оплата.
Также полезно знать, какие методы Codeception чаще всего используются. Вот небольшая таблица:
| Метод | Что делает | Пример |
|---|---|---|
| amOnPage | Переходит на указанный URL | $I->amOnPage('/site/index') |
| see | Проверяет, что текст есть на странице | $I->see('Hello') |
| fillField | Заполняет поле формы | $I->fillField('Email', 'test@test.com') |
| click | Кликает по элементу | $I->click('Submit') |
| seeInDatabase | Проверяет запись в БД | $I->seeInDatabase('users', ['email' => 'test@test.com']) |
Эти методы покроют 80% ваших задач. Остальное — дело практики.
Что в итоге?
Тестирование с Codeception в Yii2 — это не роскошь, а необходимость для любого серьёзного проекта. Оно помогает быстрее находить ошибки, не бояться рефакторинга и увереннее выпускать релизы. Да, поначалу придётся потратить время на настройку и написание первых тестов. Но потом вы скажете себе спасибо, когда тест поймает баг, который сэкономит вам несколько часов дебага.
Начните с малого: напишите пару юнит-тестов для своих моделей, потом добавьте функциональные для основных страниц. А когда освоитесь — подключите приёмочные. Постепенно вы войдёте во вкус и уже не сможете представить разработку без тестов.
Если вы хотите, чтобы ваш проект был качественным и без багов, но нет времени разбираться самостоятельно — обращайтесь в студию WNDER. Мы поможем с разработкой и тестированием.
Удачи в тестах!

