Некоторое время назад я погрузился в 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; } }
Если вы хотите больше, ознакомьтесь с презентацией Марчелло .