Статьи

PHPSpec: BDD для ваших занятий

Некоторое время назад я погрузился в Behavior-Driven Development, начав использовать Behat (PHP-эквивалент Cucumber) в katas и в PHP-приложении предприятия. Но я никогда не пытался применить подход, основанный на спецификации (в TDD, это будет сначала тест), в коде, а не в бизнес-удобочитаемом языке.

Разработка, управляемая поведением, может рассматриваться как эволюция разработки, управляемой тестами, строго в ее внешней версии и с усовершенствованным языком. В случае инструмента, который я рассматриваю сегодня, BDD реализован с кодом, а не с текстовыми файлами объектов (например, написанными в Gherkin), как в Behat.

PHPSpec похож на (или порт) RSpec, оригинального инструмента BDD Ruby. Это удовлетворяет потребность в подходе, отличном от классического xUnit на уровне класса. Вот как я их вижу:

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

По словам Марчелло , предлагаемый рабочий процесс должен начинаться с пользовательских историй и реализовывать их с помощью BDD снаружи, сначала путем определения поведения приложения с помощью Behat (бизнес-читабельные тесты), а затем углубляясь в детали классов с помощью PHPSpec. Это похоже на знаменитый двойной цикл Red-Green-Refactor — Acceptance Test-Driven Development.

BDD поддерживает различные семантики для спецификаций ваших

тестов
:

  •  Классы спецификации начинаются с Describe, а не заканчиваются Test .
  • Префикс для методов это itShould вместо test .
  • Проверка осуществляется через ожидания и спецификации , а не с помощью методов утверждения . Это приводит к коду, который звучит как английский.

Многие BDD-дружественные API были модифицированы в существующих средах тестирования: например, PHPUnit имеет метод assertThat (), который можно использовать с сопоставителями для имитации английского подобного кода.

Я думаю, что новые тестовые среды не приносят нам функциональных инноваций : мы можем делать то же самое в PHPT, PHPUnit или PHPSpec: создавать объекты, вызывать методы и проверять результаты. Здесь мы получаем новую семантику (думая о спецификациях, а не о тестах) и улучшенную поддержку внешнего рабочего процесса : начиная с функций более высокого уровня и переходя в классы, поддерживая тот же язык. Вы никогда не будете писать ненужный класс снова.

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

Реализация

Так как же работает PHPSpec? Вы расширяете базовый класс, как в PHPUnit, и предоставляете условно названные методы. Методы будут запускаться изолированно и по одному.

Вам предоставляется скрипт phpspec для запуска тестов / спецификаций. Конечно, этот скрипт загружает необходимые зависимости, так что вам не нужно ничего делать с require_once ().

Пробный запуск

Вот как можно взглянуть на PHPSpec.
Рекомендуется установка PEAR. На момент написания этой статьи:

pear channel-discover pear.phpspec.net-1.1.0beta
pear install --alldeps phpspec/PHPSpec

Возможно, вам придется обновить установку Pear до ( обновление Pear ).

—alldeps имеет фундаментальное значение, так как отсутствующий Console_Color не позволит запустить phpspec. 1.1.0 беты- суффикс , чтобы избежать груши жалуясь , что пакет не является стабильным. Я попробовал версию 1.1.1, но после этого скрипт phpspec отсутствовал.

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

Конечно, API, который вы будете использовать, не знаком. Вероятно, в будущем проекту понадобится больше документации, но это нормально, поскольку мы привыкли к огромному охвату PHPUnit (я написал об этом книгу ).

Mocks & Столбики

Вы можете использовать Mockery или Phake, PEAR-устанавливаемые независимые среды Test Double, чтобы производить Test Doubles. Существует также внутренняя реализация в отдельном пакете PEAR, PHPSpec_Mocks; его Api немного уродлив, так как он создает двойники с помощью глобальных функций, но он, вероятно, будет лучше интегрироваться из-за отсутствия кода установки и его примитивов.

Покажите нам код!

Вот мой файл DescribeFizzBuzz.php.

<?php
/**
 * FizzBuzz is a small kata where the goal is developing a simple function,
 * which we partially specify here. The function... well, we'll see if this
 * specification is clear enough for you to instantly understand what it
 * should do.
 * Disclaimer: both the specification and the code are incomplete, for the 
 * purpose of showing all the basic features of PHPSpec.
 */
class DescribeFizzBuzz extends \PHPSpec\Context
{
    private $fizzbuzz;

    public function before()
    {
        $this->fizzbuzz = new FizzBuzz();
    }

    public function itShouldReturnTheSameNumberForOrdinaryNumbers()
    {
        $this->spec($this->fizzbuzz->say(1))->should->equal(1);
        $result = $this->spec($this->fizzbuzz->say(2));
        $result->should->be(2);
    }

    public function itShouldNotReturnTheSameNumberForMultiplesOf3()
    {
        $result = $this->spec($this->fizzbuzz->say(3));
        $result->shouldNot->be(3);
        $result->should->be('Fizz');
    }

    public function itShouldBeAnObject()
    {
        $this->spec($this->fizzbuzz)->should->beAnInstanceOf('FizzBuzz');
    }

    public function itShouldNotReturnTheSameNumberForMultiplesOf5()
    {
        $this->pending('Buzz implementation needed.');
    }

    public function itShouldReturnBangForMultiplesOf7()
    {
        $this->fail('This scenario should already be specified.');
    }
}

class FizzBuzz
{
    public function say($number)
    {
        if ($number % 3 == 0) {
            return 'Fizz';
        }
        return $number;
    }
}

Если вы хотите больше, ознакомьтесь с презентацией Марчелло .