bdd для php проектов

Post on 10-May-2015

4.579 Views

Category:

Technology

3 Downloads

Preview:

Click to see full reader

TRANSCRIPT

BEHAVIORDRIVENDEVELOPMENTДЛЯ PHP ПРОЕКТОВ

@everzet

КТО Я

ПРОГРАММИСТС РОЖДЕНИЯ

DEV.BYВЕДУЩИЙ РАЗРАБОТЧИК

symfony-разработчикС 2007 годаСОЗДАТЕЛЬBEHAT

http://everzet.com

РАЗРАБОТКАINSIDE-OUT

Тесты двигателя

Тесты электрики

Тесты колес

Тесты соединений

ТЕСТЫUNIT

TDD

=качественныйпродукт?+

разработкаunit-тесты

=+разработкаunit-тесты

качественный-продукт

TDD

ОТДЕЛЬНЫХ МОДУЛЕЙНЕ ГАРАНТИРУЮТ КАЧЕСТВОРАБОТЫ СИСТЕМЫ В ЦЕЛОМ

UNIT-ТЕСТЫ

РАЗРАБОТКАOUTSIDE-IN

ВХОДНЫЕ/ВЫХОДНЫЕ

ДАННЫЕ

входныевыходные

данныеданные

RSpec

# bowling_spec.rbrequire '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 endend

<?phprequire_once 'bowling.php'

class DescribeIndexController extends PHPSpec_Context_Zend{ public function itShouldDisplayHelloWorld() { $this->get(‘index’); $this-> response()-> should-> match(‘/Hello World/’); }}

PHPSpec

<?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’, ));

Symfony Functional Test

BDD

) =качественныйпродукт

+ (

разработка

unit-тесты

+ПОВЕДЕНИЕ

ТЕХНИКАКОММУНИКАЦИЙ

ИДЕЯ

# bowling_spec.rbrequire '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 endend

ИДЕЯ

# bowling_spec.rbrequire '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 endend

NO!

ИДЕЯХочу онлайн-боулинг

с блэкджеком и...

и он будетПЛАТНЫМ

КОММУНИКАЦИИ

Хочу кастомный Porsche

написание спек

разработка

идея

# bowling_spec.rbrequire '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 endend

ФУНКЦИОНАЛ

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

ФУНКЦИОНАЛ

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

СЦЕНАРИИ

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

ШАГИ

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

БИБЛИОТЕКИ

ASSERTIONS

RUNNER

BROWSER

Test::Unit, RSpec

Webrat, Capybara, Selenium

Autotest, RStakeout, Watchr

require 'calculator'

Given /I have entered (\d+) into the calculator/ do|n| @calc.push n.to_iend

When /I press (\w+)/ do |op| @result = @calc.send opend

Then /the resoulr should be (.*)/ do |result| @result.should == result.to_fend

ОПРЕДЕЛЕНИЯ

require 'calculator'

Given /I have entered (\d+) into the calculator/ do|n| @calc.push n.to_iend

When /I press (\w+)/ do |op| @result = @calc.send opend

Then /the resoulr should be (.*)/ do |result| @result.should == result.to_fend

ОПРЕДЕЛЕНИЯ

RubyПИШУТСЯ на

МИНУСЫ

1. Не все PHP-разработчики знают/хотят знать Ruby2. Сложность при описании входных условий

4. Скорость работы кросс-языкового решения3. Невозможность использования PHP библиотек

1. Написан с нуля на PHP5.32. Написан с применением Symfony Components

4. Полностью нативное решение на PHP3. Старается быть Cucumber’ом с входными/выходными данными

6. Поддерживает полную и17ю7. Полностью расширяем и настраиваем8. Поддерживает различные типы лоадеров

5. Столь же быстр, что и Cucumber (проверено)

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

ФУНКЦИОНАЛ

<?php

$steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } });

ОПРЕДЕЛЕНИЯ

<?php

$steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } });

ОПРЕДЕЛЕНИЯ

ТИП ОПРЕДЕЛЕНИЯ

<?php

$steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } });

ОПРЕДЕЛЕНИЯ

РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ

<?php

$steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { if (‘fail’ === $success) { assertNotEquals(0, $world->return); } else { assertEquals(0, $world->return); } });

CALLBACK

ОПРЕДЕЛЕНИЯ

<?php

$steps->Then(‘/^it should (fail|pass)$/’, function($world, $status) { ... });

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’ });

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 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 Everzet\Behat\Exception\Pending();});

СТАТУСЫ

<?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’});

СТАТУСЫ

ПРИМЕРИСПОЛЬЗОВАНИЯ

УСТАНОВКА

$> pear channel-discover pear.everzet.com$> pear install everzet/behat-beta

<?php # ./user.php

class User{ public function __construct($username, $age = 1) { }

public function getName() {}

public function getAge() {}}

HOW MUCH IS THE FISH?

# ./features/user.feature# language: ru

Функционал: Базовый Пользователь Чтобы работать с пользователями Как разработчик сайта Я хочу иметь доступ к пользовательской модели

Сценарий: Создание пользователя Допустим у нас нет пользователей Если мы добавим пользователя ‘everzet’ То у нас должно быть 1 пользователей И имя у первого пользователя ‘everzet’

FEATURE

GET SNIPPETS

<?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());});

ОПРЕДЕЛЕНИЯ

WATCH IT FAILS

РЕАЛИЗАЦИЯ<?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; }}

WATCH IT PASSES

1. CommonWebSteps2. Annotated class step definitions and hooks

4. PDF/HTML formatter3. JUnit formatter

5. Selenium integration

TODO

ССЫЛКИ

ОФФИЦИАЛЬНЫЙ САЙТhttp://everzet.com/Behat

ОФФИЦИАЛЬНЫЙ РЕПОЗИТОРИЙhttp://github.com/everzet/Behat

ОФФИЦИАЛЬНАЯ GOOGLE GROUPhttp://groups.google.com/group/behat

ВОПРОСЫ?

top related