Зарегистрируйтесь для доступа к 15+ бесплатным курсам по программированию с тренажером

Модульные тесты PHP: Автоматическое тестирование

Изученной информации уже достаточно для тестирования в повседневной практике разработки. Далее мы будем погружаться в более сложные темы и возможности 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

Не всегда пограничные случаи так легко увидеть. Маловероятно, что каждый программист сможет сразу написать все нужные тесты. Если в коде возникла ошибка, для которой не было теста, нужно поступить так: сначала написать тест, который воспроизводит эту ошибку, и только потом — исправлять ее. Только так можно поддерживать достаточный уровень надежности, не превращая разработку в непрерывную починку багов.


Дополнительные материалы

  1. Чек-лист хороших инженерных практик в компаниях

Аватары экспертов Хекслета

Остались вопросы? Задайте их в разделе «Обсуждение»

Вам ответят команда поддержки Хекслета или другие студенты

Об обучении на Хекслете

Для полного доступа к курсу нужен базовый план

Базовый план откроет полный доступ ко всем курсам, упражнениям и урокам Хекслета, проектам и пожизненный доступ к теории пройденных уроков. Подписку можно отменить в любой момент.

Получить доступ
1000
упражнений
2000+
часов теории
3200
тестов

Открыть доступ

Курсы программирования для новичков и опытных разработчиков. Начните обучение бесплатно

  • 130 курсов, 2000+ часов теории
  • 1000 практических заданий в браузере
  • 360 000 студентов
Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»

Наши выпускники работают в компаниях:

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Занимайтесь созданием сайтов, веб-приложений, сервисов и их интеграцией с внутренними бизнес-системами на бекенд-языке PHP
10 месяцев
с нуля
Старт 3 октября

Используйте Хекслет по-максимуму!

  • Задавайте вопросы по уроку
  • Проверяйте знания в квизах
  • Проходите практику прямо в браузере
  • Отслеживайте свой прогресс

Зарегистрируйтесь или войдите в свой аккаунт

Отправляя форму, вы принимаете «Соглашение об обработке персональных данных» и условия «Оферты», а также соглашаетесь с «Условиями использования»