Изученной информации уже достаточно для тестирования в повседневной практике разработки. Перед тем, как погружаться в более сложные темы и возможности PHPUnit, пройдём полный путь тестирования библиотеки, поговорим об организации тестов, хороших и плохих практиках. Это поможет сформировать правильное отношение к тестированию в целом.
В этом уроке мы разберём основы модульного тестирования. Это тестирование направлено на проверку модулей программы в изоляции от всех остальных частей. Эти тесты обычно тестируют базовые конструкции языка: функции, модули, классы. Такие тесты не дают никаких гарантий работы всего приложения в целом, но хорошо помогают тогда, когда какой-то модуль программы имеет сложную логику.
Попробуем протестировать стек. Напомню, что стек представляет собой список элементов организованных по принципу LIFO. Данные кладутся в стек в одном порядке, а извлекаются в обратном. Сам стек, как правило, используется для реализации алгоритмов. Он часто используется в низкоуровневом коде: например, внутри языков программирования или в операционных системах.
<?php
// Вымышленная библиотека
use Stack;
$stack = Stack\make();
Stack\isEmpty($stack); // true
Stack\push($stack, 1); // (1)
Stack\push($stack, 2); // (2, 1)
Stack\push($stack, 3); // (3, 2, 1)
Stack\isEmpty($stack); // false
Stack\pop($stack); // 3. В стеке (2, 1)
Stack\pop($stack); // 2. В стеке (1)
Stack\pop($stack); // 1. В стеке пусто
Stack\isEmpty($stack); // true
Сначала решим организационные вопросы. Если предположить, что реализация стека лежит в файле src/Stack.php, то его тест мы положим в файл tests/StackTest.php.
Теперь напишем первый тест. Первый тест всегда должен проверять позитивный сценарий — тот, в котором задействована основная функциональность тестируемого компонента:
<?php
namespace Hexlet\Phpunit\Tests;
use PHPUnit\Framework\TestCase;
use Hexlet\Phpunit\Stack;
class StackTest extends TestCase
{
public function testMainFlow(): void
{
$stack = Stack\make();
// Добавляем два элемента в стек и затем извлекаем их
Stack\push($stack, 'one');
Stack\push($stack, 'two');
$value1 = Stack\pop($stack);
$this->assertEquals('two', $value1);
$value2 = Stack\pop($stack);
$this->assertEquals('one', $value2);
}
}
Этот тест проверяет, что правильно работают два основных метода без учёта пограничных случаев. Для этого внутри теста проверяются два утверждения, которые по очереди проверяют извлекаемые значения из стека.
Следующим тестом будет тест на дополнительные функции стека. К таким у нас относится функция isEmpty()
, которая проверяет, пустой ли стек:
<?php
namespace Hexlet\Phpunit\Tests
use PHPUnit\Framework\TestCase;
use Hexlet\Phpunit\Stack;
class StackTest extends TestCase
{
public function testIsEmpty(): void
{
$stack = Stack\make();
$this->assertTrue(Stack\isEmpty($stack));
Stack\push($stack, 'one');
$this->assertFalse(Stack\isEmpty($stack));
Stack\pop($stack);
$this->assertTrue(Stack\isEmpty($stack));
}
}
В этом тесте проверяются сразу три ситуации:
В принципе, этого достаточно. Хотя в теории возможны ситуации, при которых isEmpty()
всё равно сломается. Нужно ли пытаться найти все варианты? Не нужно. Тесты не даются бесплатно, каждая написанная строчка кода в проекте — потенциальное место для изменения в случае правок. Если есть сомнения, нужно ли писать проверку или нет, то лучше не пишите. Так вы поймёте тот минимум, который стоит писать, и после которого тесты писать не эффективно. Редкие ситуации требуют покрытия тестами только тогда, когда они критичны для работоспособности.
Ну, и последнее, что можно протестировать — поведение функции pop()
, когда в стеке нет ни одного элемента. По задумке, стек выбрасывает исключение, если из него попытались взять элемент, когда тот был пустой. То есть эта ситуация рассматривается как ошибочная, программист всегда должен убеждаться в том что стек не пустой. Для отлова исключений в PHPUnit используется специальное утверждение expectException()
<?php
namespace Hexlet\Phpunit\Tests
use PHPUnit\Framework\TestCase;
use Hexlet\Phpunit\Stack;
class StackTest extends TestCase
{
public function testPop(): void
{
// Ожидание ставится до вызова кода
$this->expectException(Exception::class);
$stack = Stack\make();
Stack\pop($stack); // Boom!
}
}
https://replit.com/@hexlet/php-testing-unit-tests-stack#tests/StackTest.php
Но не всегда пограничные случаи так легко увидеть. Маловероятно, что любой программист сможет сразу написать все нужные тесты. Если в коде возникла ошибка, для которой не было теста, то сначала напишите тест, который воспроизводит эту ошибку, и затем уже чините её. Только так можно поддерживать достаточный уровень надёжности, не превращая разработку в непрерывную починку багов.
Вам ответят команда поддержки Хекслета или другие студенты.
Выделите текст, нажмите ctrl + enter и отправьте его нам. В течение нескольких дней мы исправим ошибку или улучшим формулировку.
Загляните в раздел «Обсуждение»:
Статья «Ловушки обучения»
Вебинар «Как самостоятельно учиться»
Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.
Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно.
Наши выпускники работают в компаниях:
С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.
Зарегистрируйтесь или войдите в свой аккаунт