Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

BDD для PHP проектов

5,969 views

Published on

  • Be the first to comment

BDD для PHP проектов

  1. 1. BEHAVIOR DRIVEN DEVELOPMENT ДЛЯ PHP ПРОЕКТОВ @everzet
  2. 2. КТО Я symfony-разработчик С 2007 года СОЗДАТЕЛЬ BEHAT ВЕДУЩИЙ РАЗРАБОТЧИК DEV.BY ПРОГРАММИСТ С РОЖДЕНИЯ http://everzet.com
  3. 3. РАЗРАБОТКА INSIDE-OUT
  4. 4. Тесты соединений Тесты двигателя Тесты колес UNIT Тесты электрики ТЕСТЫ
  5. 5. TDD + = ? качественный unit-тесты разработка продукт
  6. 6. TDD + = качественный- unit-тесты разработка продукт
  7. 7. UNIT-ТЕСТЫ ОТДЕЛЬНЫХ МОДУЛЕЙ НЕ ГАРАНТИРУЮТ КАЧЕСТВО РАБОТЫ СИСТЕМЫ В ЦЕЛОМ
  8. 8. РАЗРАБОТКА OUTSIDE-IN
  9. 9. ВХОДНЫЕ/ВЫХОДНЫЕ ДАННЫЕ выходные входные данные данные
  10. 10. RSpec # bowling_spec.rb require 'bowling' describe Bowling, "#score" do it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should == 0 end end
  11. 11. PHPSpec <?php require_once 'bowling.php' class DescribeIndexController extends PHPSpec_Context_Zend { public function itShouldDisplayHelloWorld() { $this->get(‘index’); $this-> response()-> should-> match(‘/Hello World/’); } }
  12. 12. Symfony Functional Test <?php $browser->get(‘/job/new’)-> with(‘request’)->begin()-> isParameter(‘module’, ‘job’)-> isParameter(‘action’, ‘new’)-> end()-> click(‘Preview your job’, array(‘job’ => array( ‘company’ => ‘Sensio Labs’, ‘url‘ => ‘http://sensio.com’, ‘logo‘ => ‘/uploads/jobs/sensio-labs.gif’, ));
  13. 13. BDD unit-тесты +( + )= качественный ПОВЕДЕНИЕ продукт разработка
  14. 14. ТЕХНИКА КОММУНИКАЦИЙ
  15. 15. ИДЕЯ # bowling_spec.rb require 'bowling' describe Bowling, "#score" do it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should == 0 end end
  16. 16. ИДЕЯ # bowling_spec.rb NO! require 'bowling' describe Bowling, "#score" do it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should == 0 end end
  17. 17. ИДЕЯ Хочу онлайн-боулинг с блэкджеком и... и он будет ПЛАТНЫМ
  18. 18. КОММУНИКАЦИИ Хочу кастомный Porsche # bowling_spec.rb require 'bowling' describe Bowling, "#score" do it "returns 0 for all gutter game" do bowling = Bowling.new 20.times { bowling.hit(0) } bowling.score.should == 0 end end разработка написание спек идея
  19. 19. ФУНКЦИОНАЛ Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario: Add two numbers Given I have entered 10 into the calculator And I have entered 5 into the calculator When I press ‘plus’ Then the result should be 15
  20. 20. ФУНКЦИОНАЛ Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario: Add two numbers Given I have entered 10 into the calculator And I have entered 5 into the calculator When I press ‘plus’ Then the result should be 15
  21. 21. СЦЕНАРИИ Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario: Add two numbers Given I have entered 10 into the calculator And I have entered 5 into the calculator When I press ‘plus’ Then the result should be 15
  22. 22. ШАГИ Feature: Addition In order to avoid silly mistakes As a math idiot I want to be told the sum of two numbers Scenario: Add two numbers Given I have entered 10 into the calculator And I have entered 5 into the calculator When I press ‘plus’ Then the result should be 15
  23. 23. БИБЛИОТЕКИ ASSERTIONS Test::Unit, RSpec BROWSER Webrat, Capybara, Selenium RUNNER Autotest, RStakeout, Watchr
  24. 24. ОПРЕДЕЛЕНИЯ require 'calculator' Given /I have entered (d+) into the calculator/ do |n| @calc.push n.to_i end When /I press (w+)/ do |op| @result = @calc.send op end Then /the resoulr should be (.*)/ do |result| @result.should == result.to_f end
  25. 25. ОПРЕДЕЛЕНИЯ require 'calculator' Given /I have entered (d+) into the calculator/ do |n| ПИШУТСЯ на Ruby @calc.push n.to_i end When /I press (w+)/ do |op| @result = @calc.send op end Then /the resoulr should be (.*)/ do |result| @result.should == result.to_f end
  26. 26. МИНУСЫ 1. Не все PHP-разработчики знают/хотят знать Ruby 2. Сложность при описании входных условий 3. Невозможность использования PHP библиотек 4. Скорость работы кросс-языкового решения
  27. 27. 1. Написан с нуля на PHP5.3 2. Написан с применением Symfony Components 3. Старается быть Cucumber’ом с входными/выходными данными 4. Полностью нативное решение на PHP 5. Столь же быстр, что и Cucumber (проверено) 6. Поддерживает полную и17ю 7. Полностью расширяем и настраиваем 8. Поддерживает различные типы лоадеров
  28. 28. ФУНКЦИОНАЛ Feature: Serve coffee In order to earn money Customers should be able to buy coffee at all times Scenario: Buy last coffee Given there are 1 coffees left in the machine And I have deposited 1$ When I press the coffee button Then I should be served a coffee
  29. 29. ОПРЕДЕЛЕНИЯ <?php $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } } );
  30. 30. ОПРЕДЕЛЕНИЯ <?php ТИП ОПРЕДЕЛЕНИЯ $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } } );
  31. 31. ОПРЕДЕЛЕНИЯ <?php РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } } );
  32. 32. ОПРЕДЕЛЕНИЯ <?php $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { CALLBACK assertEquals(0, $world->return); } } );
  33. 33. ИСПОЛНЕНИЕ Feature: Behat Console Runner Scenario: Run feature from CLI Given I have default Behat configuration When I call ‘behat -f progress’ Then it should pass <?php $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { ... } );
  34. 34. ИСПОЛНЕНИЕ Feature: Behat Console Runner Scenario: Run feature from CLI Given I have default Behat configuration When I call ‘behat -f progress’ Then it should pass <?php $steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { // $status == ‘pass’ } );
  35. 35. СТАТУСЫ <?php $steps->Then(‘/^it should pass$/’, function($world) { return true; }); $steps->Then(‘/^it passes$/’, function($world) { return false; }); $steps->Then(‘/^it should fail$/’, function($world) { throw new Exception(); }); $steps->Then(‘/^it should pend$/’, function($world) { throw new EverzetBehatExceptionPending(); });
  36. 36. СТАТУСЫ <?php $steps->Then(‘/^it should pass$/’, function($world) { ... }); $steps->Then(‘/^it should pass$/’, function($world) { // Will throw exception on definitions read }); $steps->Then(‘/^it’s good$/’, function($world) { ... }); $steps->Then(‘/^it’s w+$/’, function($world) { // Will throw exception on ‘it should pass call’ });
  37. 37. ПРИМЕР ИСПОЛЬЗОВАНИЯ
  38. 38. УСТАНОВКА $> pear channel-discover pear.everzet.com $> pear install everzet/behat-beta
  39. 39. HOW MUCH IS THE FISH? <?php # ./user.php class User { public function __construct($username, $age = 1) { } public function getName() {} public function getAge() {} }
  40. 40. FEATURE # ./features/user.feature # language: ru Функционал: Базовый Пользователь Чтобы работать с пользователями Как разработчик сайта Я хочу иметь доступ к пользовательской модели Сценарий: Создание пользователя Допустим у нас нет пользователей Если мы добавим пользователя ‘everzet’ То у нас должно быть 1 пользователей И имя у первого пользователя ‘everzet’
  41. 41. GET SNIPPETS
  42. 42. ОПРЕДЕЛЕНИЯ <?php # ./features/steps/user_steps.php require_once ‘PHPUnit/Autoload.php’; require_once ‘PHPUnit/Framework/Assert/Functions.php’; require_once __DIR__ . ‘/../../user.php’; $steps-> Допустим(‘/^у нас нет пользователей$/’, function($world) { $world->users = array(); })-> Если(‘/^мы добавим пользователя ’([^’]+)’$/’, function($world, $username) { $world->users[] = new User($username); })-> To(‘/^у нас должно быть (d+) пользователей$/’, function($world, $count) { assertEquals($count, count($world->users)); })-> То(‘/^имя у первого пользователя ’([^’]+)’$/’, function($world, $username) { assertEquals($username, $world->users[0]->getName()); });
  43. 43. WATCH IT FAILS
  44. 44. РЕАЛИЗАЦИЯ <?php # ./user.php class User { protected $name, $age; public function __construct($username, $age = 1) { $this->name = $username; $this->age = $age; } public function getName() { return $this->name; } public function getAge() { return $this->age; } }
  45. 45. WATCH IT PASSES
  46. 46. TODO 1. CommonWebSteps 2. Annotated class step definitions and hooks 3. JUnit formatter 4. PDF/HTML formatter 5. Selenium integration
  47. 47. ССЫЛКИ ОФФИЦИАЛЬНЫЙ САЙТ http://everzet.com/Behat ОФФИЦИАЛЬНЫЙ РЕПОЗИТОРИЙ http://github.com/everzet/Behat ОФФИЦИАЛЬНАЯ GOOGLE GROUP http://groups.google.com/group/behat
  48. 48. ВОПРОСЫ?
  49. 49. CREDITS http://www.flickr.com/photos/jasmic/279741827 http://www.flickr.com/photos/mulmatsherm/2312688473 http://www.flickr.com/photos/joshfassbind/4584323789 http://www.flickr.com/photos/bearuk/564788081 http://www.flickr.com/photos/jasmincormier/3511034253 http://www.flickr.com/photos/chuqui/4552338602

×