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

Плохие и хорошие практики тестирования PHP: Автоматическое тестирование

Как и любой другой код, тесты можно писать по-разному, в том числе очень плохо. Помимо каких-то общих практик и стандартов кодирования, у тестов есть свои особенности, о которых надо знать. В этом уроке мы пройдемся по некоторым из них.

Взаимное влияние тестов

Одно из ключевых правил — тесты не должны влиять друг на друга. Это значит, что любой тест выполняется так, как будто других тестов не существует в природе.

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

  • Упасть там, где не должны падать
  • Успешно пройти там, где не должны проходить

Кроме этого, в такой ситуации вводится неопределенность. Такие тесты иногда могут падать без видимых причин. Например, когда тест запускают изолированно, то он работает, а когда вместе с остальными — падает:

<?php

class SomeTest extends TestCase
{
    private $user;

    public function testOne(): void
    {
        $this->user = ['name' => 'Vasya'];
    }

    public function testTwo(): void
    {
        // Здесь используется пользователь, которого создал другой тест
        // Этот тест зависит от работы предыдущего теста
        // Он не может работать без последовательного запуска обоих тестов
        $this->user['name'] = 'Petya';
    }
}

Особенно часто такая ситуация возникает в тестах, активно взаимодействующих с внешней средой — базой данных или файловой системой. Тестирование побочных эффектов имеет свои хитрости и рассматривается в курсе по продвинутому тестированию.

Условные конструкции в тесте

Перейдем к условным конструкциям:

<?php

class SomeTest extends TestCase
{
    public function testSomething(): void
    {
        if (/* что-нибудь */) {
        // Выполняем код одним способом
        // Здесь может быть проверка
        } else {
        // Выполняем код другим способом
        // Здесь может быть проверка
        }
        // Здесь может быть проверка
    }
}

Фактически, любое ветвление внутри тестов — это несколько тестов в рамках одного теста. Надо от этого избавляться и никогда так не писать.

Тест вне тестов

Задача setUp — готовить данные и среду для тестирования, а задача test — вызывать тестируемый код и проводить проверки. Но иногда разработчики переусердствуют:

<?php

class SomeTest extends TestCase
{
    private $result;

    public setUp(): void
    {
        // Вызывается тестируемый код, что противоречит идее setUp
        $this->result = sum(5, 9);
    }

    public function testSum(): void
    {
        $this->assertEquals(14, $this->result);
    }
}

В этом примере тестируемый код вызывается в setUp. Такой подход усложняет анализ тестов, потому что переворачивает все с ног на голову.

Слишком сильная детализация

Под влиянием голосов из интернета программисты стремятся максимально разносить код по файлам, модулям и функциям. То же самое наблюдается и в тестах. Вместо одного теста со всеми необходимыми проверками новички иногда создают по пять тестов, в каждом из которых ровно одна проверка:

<?php

class SomeTest extends TestCase
{
    public function testAge(): void
    {
        $user = ['name' => 'Mark', 'age' => 28];

        // Здесь код, добавляющий пользователя в базу данных
        $this->assertEquals(28, $user['age']);
    }

    public function testName(): void
    {
        $user = ['name' => 'Mark', 'age' => 28];
        // Здесь код, добавляющий пользователя в базу данных

        $this->assertEquals('Mark', $user['name']);
    }
}

Чаще всего, единственным результатом такого разделения будет слишком большой объем кода и сложный рефакторинг в будущем, когда кода станет по-настоящему много.

Код с тестами писать дольше, чем код без тестов

Это очень интересный вопрос, по которому можно понять, насколько хорошо программист пишет тесты. Некоторые виды тестирования действительно сложны и требуют дополнительного времени, но ежедневные тесты, которые пишутся вместе с кодом, должны приводить к ускорению разработки. И на это есть пять причин:

  • Тесты влияют на дизайн кода, помогая раньше выявлять неудачные решения
  • Тесты упрощают подготовку входных данных, ведь с ними она проводится всего один раз
  • Тесты упрощают проверку кода — они сами проверяют все, включая пограничные случаи
  • Тесты позволяют реже проверять код вручную, что ускоряет рефакторинг
  • Тесты снижают уровень стресса

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

  1. Начинаем писать тесты правильно

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

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

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

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

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

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

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

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

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

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

Логотип компании Альфа Банк
Логотип компании Aviasales
Логотип компании Yandex
Логотип компании Tinkoff
Рекомендуемые программы
профессия
от 25 000 ₸ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 28 ноября

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

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

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

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