Статьи

Тестирование ваших тестов? Кто смотрит на сторожей?

Независимо от того, работаете ли вы в большой корпорации, стартапе или просто для себя, модульное тестирование не только полезно, но и часто необходимо. Мы используем модульные тесты для тестирования нашего кода, но что произойдет, если наши тесты будут неправильными или неполными? Что мы можем использовать для тестирования наших тестов? Кто смотрит на сторожей?

Кто смотрит на граффити сторожей

Введите тестирование мутации

Нет, нет, ничего такого. Mutation Testing (или Mutant Analysis ) — это метод, используемый для создания и оценки качества тестов программного обеспечения. Он состоит из модификации тестов очень маленькими способами. Каждая измененная версия называется мутантом, и тесты обнаруживают и отклоняют мутанты, заставляя поведение исходной версии отличаться от мутанта. Мутации — это ошибки в нашем исходном коде, и анализ проверяет, обнаруживают ли наши тесты эти ошибки. Короче говоря, если тест все еще работает после того, как он мутировал, это не очень хороший тест.

Тестирование мутаций с помощью Humbug

Humbug — это среда тестирования мутаций для PHP.

Чтобы Humbug мог генерировать покрытие кода, нам нужно будет установить и включить XDebug на нашем компьютере. Затем мы можем установить его как глобальный инструмент.

composer global require 'humbug/humbug'

После этого, если мы запустим

 humbug

команда, мы должны быть в состоянии увидеть некоторую информацию об установке Humbug и ошибку, указывающую на то, что у нас нет файла humbug.json

Бутстрапирование

Перед настройкой и использованием Humbug нам нужен проект, который мы можем протестировать. Мы создадим небольшой пакет калькулятора PHP, в котором будем запускать наши юнит-тесты и мутационные тесты.

Давайте создадим папку /Calculator Внутри него давайте создадим наши папки /src/tests Внутри нашей папки /src папка /tests Нам также нужно будет использовать PHPUnit в нашем пакете. Лучший способ сделать это — использовать Composer . Давайте установим PHPUnit с помощью следующей команды:

 composer global require phpunit/phpunit

Давайте создадим наш калькулятор. Внутри папки /srcCalculator.php

 <?php

namespace package\Calculator;

class Calculator {

    /**
     * BASIC OPERATIONS
     */
    public function add($a1, $a2) {
        return $a1 + $a2;
    }

    public function subtract($a1, $a2) {
        return $a1 - $a2;
    }

    public function multiply($a1, $a2) {
        return $a1 * $a2;
    }

    public function divide($a1, $a2) {

        if ($a2 === 0) {
            return false;
        }

        return $a1 / $a2;
    }

    /*
     * PERCENTAGE
     */

    //This will return $a1 percent of $a2
    public function percentage($a1, $a2) {
        return ( $a1 / $a2 ) * 100;
    }

    /*
     * PI
     */

    //Returns the value of pi
    public function pi() {
        return pi();
    }

    /*
     * LOGARITHMIC
     */

    //Returns the basic logarithm in base 10
    public function log($a) {
        return log10($a);
    }

}

Это довольно простая программа. Простой калькулятор, с основными арифметическими, процентными и логарифмическими операциями и функцией для возврата значения pi . Далее, внутри нашей папки /tests Если вам нужна помощь с модульным тестированием в PHP, ознакомьтесь с этим руководством .

Создайте файл CalculatorTest.php и добавьте следующее:

 <?php

use package\Calculator\Calculator;

class CalculatorTest extends PHPUnit_Framework_TestCase {

    public function testAdd() {
        $calculator = new Calculator();
        $result = $calculator->add(2, 3);
        $this->assertEquals($result, 5);
    }

    public function testSubtract() {
        $calculator = new Calculator();
        $result = $calculator->subtract(6, 3);
        $this->assertEquals($result, 3);
    }

    public function testMultiply() {
        $calculator = new Calculator();
        $result = $calculator->multiply(6, 3);
        $this->assertEquals($result, 18);
    }

    public function testDivide() {
        $calculator = new Calculator();
        $result = $calculator->divide(6, 3);
        $this->assertEquals($result, 2);
    }

}

Это будет наш начальный тестовый стек. Если мы запустим команду phpunit Важно, чтобы все наши тесты прошли, иначе Humbug потерпит неудачу.

Настройка Humbug

Humbug можно настроить вручную, создав файл humbug.json.dist

 humbug configure

Запуск команды попросит у нас ответы на некоторые вопросы:

  • Какие исходные каталоги вы хотите включить?

    В этом мы пойдем с src /, каталогом нашего исходного кода.

  • Какие каталоги вы хотите исключить из вашего исходного каталога?

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

  • Тайм-аут одного набора тестов в секундах.

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

  • Где вы хотите хранить свой текстовый журнал?

    humblog.txt

  • Где вы хотите хранить свой журнал JSON (если вам это нужно)?

    Значение по умолчанию пустое, но мы будем хранить его в humblogjson.json

  • Сгенерировать «humblog.json.dist»?

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

Используя Humbug

Теперь, когда наше приложение запущено с тестами и установлен Humbug, давайте запустим Humbug и проверим результаты.

    humbug

Результат должен быть близок к этому:

Обманная обратная связь

Интерпретация результатов Humbug

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

Убитый мутант (.) — это мутация, которая провалила тест. Не смущайтесь, это положительный результат!

Экранированная мутация (M) — это мутация, при которой тест еще не пройден. Это не положительный результат, мы должны вернуться к нашему тесту и проверить, чего не хватает.

Непокрытая мутация (S) — это мутация, которая возникает в линии, не охваченной модульным тестом.

Фатальные ошибки (E) и таймауты (T) — это мутации, которые создали фатальные ошибки, и мутации, которые создают бесконечные циклы, соответственно.

Как насчет метрик?

Индикатор показателя мутации указывает процент сгенерированных мутаций, которые были обнаружены. Мы хотим стремиться к 100%.

Охват мутационного кода указывает процент тестов, покрытых мутациями.

Индикатор оценки мутации дает представление о том, насколько эффективны реально существующие тесты.

Анализируя наш лживый журнал, мы видим, что у нас есть 9 не охваченных мутантов, и некоторые действительно плохие показатели. Взгляните на файл humblogjson.json Этот файл был сгенерирован автоматически так же, как файл humblog.txt Мы не проверяли наши функции процента, числа пи и логарифма. Также нам нужно охватить случай, когда мы делим число на 0. Давайте добавим еще несколько тестов, чтобы охватить отсутствующие ситуации:

     public function testDivideByZero() {
        $calculator = new Calculator();
        $result = $calculator->divide(6, 0);
        $this->assertFalse($result);
    }

    public function testPercentage() {
        $calculator = new Calculator();
        $result = $calculator->percentage(2, 50);
        $this->assertEquals($result, 4);
    }

    public function testPi() {
        $calculator = new Calculator();
        $result = $calculator->pi();
        $this->assertEquals($result, pi());
    }

    public function testLog() {
        $calculator = new Calculator();
        $result = $calculator->log(10);
        $this->assertEquals($result, 1);
    }

На этот раз 100% означает, что все мутации были уничтожены и что у нас есть полный охват кода.

Downsides

Самым большим недостатком тестирования мутаций и, как следствие, Humbug, является производительность. Мутационное тестирование — это медленный процесс, поскольку он зависит от множества факторов, таких как взаимодействие между строками кода, количество тестов, уровень покрытия кода и производительность как кода, так и тестов. Humbug также выполняет начальные тестовые прогоны, регистрацию и покрытие кода, которые увеличивают общую продолжительность.

Кроме того, Humbug специфичен для PHPUnit, что может быть проблемой для тех, кто использует другие платформы тестирования.

Тем не менее, Humbug находится в стадии активного развития и будет продолжать улучшаться.

Вывод

Humbug может быть важным инструментом для поддержания долговечности вашего приложения. По мере увеличения сложности вашего приложения возрастает и сложность ваших тестов — и иметь их все время на все 100% становится невероятно важным, особенно при работе с корпоративными экосистемами.

Код, который мы использовали в этом руководстве, можно клонировать здесь .

Вы использовали Humbug? Вы проводите мутацию по-другому? Дайте нам свои мысли обо всем этом!