BDD в PHP с Behat и Mink
Upcoming SlideShare
Loading in...5
×
 

BDD в PHP с Behat и Mink

on

  • 5,489 views

История и примеры использования BDD в PHP и ZF с помощью Behat и Mink.

История и примеры использования BDD в PHP и ZF с помощью Behat и Mink.

Statistics

Views

Total Views
5,489
Views on SlideShare
5,440
Embed Views
49

Actions

Likes
13
Downloads
54
Comments
0

5 Embeds 49

http://coderwall.com 44
http://twitter.com 2
http://dev53.quartsoft.com 1
http://www.linkedin.com 1
https://twitter.com 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

CC Attribution License

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

BDD в PHP с Behat и Mink BDD в PHP с Behat и Mink Presentation Transcript

  • BDD в php
  • Якто такой @ everzet senior from-birth web developer в
  • Якто такой International speaker Разработчик Behat, Mink http://github.com/everzet Разработчик jade.php http://card.everzet.com Разработчик capifony everzet@knplabs.com Core-contributor Symfony2 framework Разработчик плагинов symfony и Symfony2 @ everzet senior from-birth web developer в
  • BDD, Symfony2 эксперты Активные контрибуторы в open-source проекты Консультанты, аудиторы, тренерыhttp://knplabs.com
  • История тестирования
  • История UnitTest Автоматизация тестов
  • TDD Тесты впередИстория UnitTest Автоматизация тестов
  • BDD Dan North TDD Тесты впередИстория UnitTest Автоматизация тестов
  • BDD ⎯ эволюция TDD
  • - Эволюция-хренолюция... Что не так с TDD?
  • Test-Driven Development
  • Мы на самом деле говорим о тестах??? Но каким образом тестировать то, чего еще нет?Test-Driven Development
  • На самом деле, мы говорим о дизайне Test-Driven Development
  • BehaviorTest-Driven Development © 2003, Dan North
  • BDD был создан как набор конвенций поверх TDD
  • BDD был создан как набор конвенций поверх TDDТест-кейсы должы составлять предложенияtestFindsCustomerById()testFailsForDuplicateCustomers()
  • BDD был создан как набор конвенций поверх TDDТест-кейсы должы составлять предложенияtestFindsCustomerById()testFailsForDuplicateCustomers()Тест-кейсы должны начинаться со слова “should”shouldFindCustomerById()shouldFailForDuplicateCustomers()
  • BDD был создан как набор конвенций поверх TDDТест-кейсы должы составлять предложенияtestFindsCustomerById()testFailsForDuplicateCustomers()Тест-кейсы должны начинаться со слова “should”shouldFindCustomerById()shouldFailForDuplicateCustomers()Класс тест-кейсов должен представлять из себя существительное для кейсовclass CustomerTableTest extends PHPUnitTestCase{ /** * @Test */ shouldFindCustomerById() ...}
  • АССЕРШЕНЫ тоже TEST-ориентированы
  • АССЕРШЕНЫ тоже TEST-ориентированы ТЕСТируем assertEquals($expected, $actual)assertGreaterThan($expected, $actual) assertInstanceOf($class, $actual)
  • АССЕРШЕНЫ тоже TEST-ориентированы ТЕСТируем Описываем assertEquals($expected, $actual) $actual should be Equals to $expectedassertGreaterThan($expected, $actual) $actual should be GreaterThan $expected assertInstanceOf($class, $actual) $actual should be InstanceOf $class
  • Specификационные BDD Фрэймворки
  • *Spec RSpec by Dave Astels
  • *Spec RSpec by Dave Astels JSpec by TJ Holowaychuk
  • *Spec RSpec by Dave Astels JSpec by TJ Holowaychuk Fabulous by Alex Rudakov
  • 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
  • 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 Пишем СПЕЦИФИКАЦИЮ, а не UnitTEST
  • История Сначала дизайн Spec BDD UnitTest TDD BDD Тесты вперед Автоматизация тестов Dan North
  • СЦЕНАРНЫЙBDD photo by dsearls
  • СЛ ОВАРЬ photophoto by dsearls by Horia Varlan
  • о в р с те я те длСЛ ОВАРЬ photophoto by dsearls by Horia Varlan
  • о в р с те я те длСЛ ОВАРЬ дл яа на ли ти ко в photophoto by dsearls by Horia Varlan
  • о в р с те я те дл в СЛ ОВАРЬ дл о яа п ер на ло в е ли де тидля ко в photophoto by dsearls by Horia Varlan
  • для в зак р о азч с те и ко я те в дл в СЛ ОВАРЬ дл о яа п ер на ло в е ли де тидля ко в photophoto by dsearls by Horia Varlan
  • для в зак р о азч с те 1 и ко я те в дл в СЛ ОВАРЬ дл о яа п ер на ло в е ли де тидля ко в photophoto by dsearls by Horia Varlan
  • ИСКОРЕНИТ множество проблем ДИЗАЙНА и КОММУНИКАЦИЙ 1 те ры т есзаказчики девелоперы СЛ ОВАРЬ ана лит ики photophoto by dsearls by Horia Varlan
  • НИК АЦИИК ОММУ photo by joshfassbind.com
  • Наратив: In order to [A] As a [B] I need [C]
  • Наратив: Чтобы [A] В качестве [B] Мне нужно [C]
  • Наратив: Чтобы [A] В качестве [B] Мне нужно [C] A ⎯ добавочное знач. (профит) функционала B ⎯ профитирующая персона (роль) C ⎯ функционал
  • Наратив: Чтобы [A] В качестве [B] ⎯ Сила данной конструкции в том, что она требует определения профита от функционала еще до его реализации Мне нужно [C] © Dan North A ⎯ добавочное знач. (профит) функционала B ⎯ профитирующая персона (роль) C ⎯ функционал
  • Поведение story ⎯это ее приемочныйкритерий!⎯ если система удовлетворяет всеприемочные критерии, то она работаетверно; если не выполняет - неверно.
  • Story:In order to ...As a ...I need ...
  • Story:In order to ...As a ...I need ... Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
  • Story:In order to ...As a ...I need ... Given some initial context (the givens), When an event occurs, Then ensure some outcomes. Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
  • Story:In order to ...As a ...I need ... Scenario 1: Given some initial context (the givens), When an event occurs, Then ensure some outcomes. Scenario 2: Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
  • История Сначала дизайн Spec BDD UnitTest TDD BDD Scenario BDD Сначала анализ Тесты вперед Автоматизация тестов Dan North
  • История Сначала дизайн Spec BDD + UnitTest TDD BDD Scenario BDD Сначала анализ Тесты вперед Автоматизация тестов Dan North
  • GHERKINDSL photo by isobel.gordon
  • Story:In order to ...As a ...I need ... Scenario 1: Given some initial context (the givens), When an event occurs, Then ensure some outcomes. Scenario 2: Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
  • Feature: Feature descriptionIn order to ...As a ...I need ... Scenario: 1st scenario title Given some initial context (the givens), When an event occurs, Then ensure some outcomes. Scenario: 2nd scenario title Given some initial context (the givens), When an event occurs, Then ensure some outcomes.
  • feature treeFeature: Feature description 1. featureIn order to ...As a ...I need ... Scenario: 1st scenario title2. scenario Given some initial context (the givens) 3. step When an event occurs ... Then ensure some outcomes ... Scenario: 2nd scenario title2. scenario Given some initial context (the givens) 3. step When an event occurs ... Then ensure some outcomes ...
  • Feature: Feature descriptionIn order to ...As a ...I need ... Scenario: 1st scenario title Given some initial context (the givens) When an event occurs Then ensure some outcomes Scenario: 2nd scenario title Given some initial context (the givens) When an event occurs Then ensure some outcomes
  • # language: frFonctionnalité: Feature descriptionIn order to ...As a ...I need ... Scénario: 1st scenario title Etant donné some initial context (the givens) Lorsque an event occurs Alors ensure some outcomes Scénario: 2nd scenario title Etant donné some initial context (the givens) Lorsque an event occurs Alors ensure some outcomes
  • # language: ja : Feature descriptionIn order to ...As a ...I need ... : 1st scenario title some initial context (the givens) an event occurs ensure some outcomes : 2nd scenario title some initial context (the givens) an event occurs ensure some outcomes
  • # language: ruФункционал: Feature descriptionIn order to ...As a ...I need ... Сценарий: 1st scenario title Допустим some initial context (the givens) Когда an event occurs То ensure some outcomes Сценарий: 2nd scenario title Допустим some initial context (the givens) Когда an event occurs То ensure some outcomes
  • # language: en-pirateAhoy matey!: Feature descriptionIn order to ...As a ...I need ... Heave to: 1st scenario title Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes Heave to: 2nd scenario title Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes
  • # language: en-pirateAhoy matey!: Heave to: Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes Heave to: Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes
  • Приемочные критериидолжны быть исполняемы!
  • Установка 1. Добавляем pear-channel: $ pear channel-discover pear.behat.org 2. Ставим: $ pear install behat/behat 3. Инициализируем: $ cd path/to/project && behat --init
  • Установка 1. Добавляем pear-channel: $ pear channel-discover pear.behat.org 2. Ставим: $ pear install behat/behat 3. Инициализируем: $ cd path/to/project && behat --init +d features - place your *.feature files here +d features/steps - place step definition files here +f features/steps/steps.php - place some step definitions in this file +d features/support - place support scripts and static files here +f features/support/bootstrap.php - place bootstrap scripts in this file +f features/support/env.php - place environment initialization scripts in this file
  • # language: ruФункционал: Утилита lsЧтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий
  • # language: ruФункционал: Утилита lsЧтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий Сценарий: 2 файла в директории
  • # language: ruФункционал: Утилита lsЧтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий Сценарий: 2 файла в директории Допустим я нахожусь в директории “test1” Если я исполню “ls” То я должен увидеть: """ file_one.txt file_foo.txt """
  • # language: ru 1. feature Функционал: Утилита ls Чтобы узнать содержимое директории Как пользователь UNIX Я должен иметь утилиту листинга директорий Сценарий: 2 файла в директории Допустим я нахожусь в директории “test1”2. scenario Если я исполню “ls” То я должен увидеть: """ file_one.txt file_foo.txt """
  • # language: ruФункционал: Утилита lsЧтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий Сценарий: 2 файла в директории Допустим я нахожусь в директории “test1” Если я исполню “ls” То я должен увидеть: """ file_one.txt file_foo.txt """
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1”
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php Допустим(/^я нахожусь в директории “(.*)”$/);
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); ??? } );
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();2. Undefined шаг ⎯ у которого нет (не найдено) определений
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();2. Undefined шаг ⎯ у которого нет (не найдено) определений3. Ambiguous шаг ⎯ который подпадает под несколько определений
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();2. Undefined шаг ⎯ у которого нет (не найдено) определений3. Ambiguous шаг ⎯ который подпадает под несколько определений4. Failed шаг ⎯ который throw Exception();
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();2. Undefined шаг ⎯ у которого нет (не найдено) определений3. Ambiguous шаг ⎯ который подпадает под несколько определений4. Failed шаг ⎯ который throw Exception();5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии
  • ТИПЫРЕЗУЛЬТАТОВШАГОВ1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();2. Undefined шаг ⎯ у которого нет (не найдено) определений3. Ambiguous шаг ⎯ который подпадает под несколько определений4. Failed шаг ⎯ который throw Exception();5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии6. Passed шаг ⎯ который не кидает эксепшенов
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); } );Если я исполню “ls”
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function() { throw new BehatBehatExceptionPending(); } );Если я исполню “ls” <?php $steps->Если(/^я исполню “(.*)”$/, function($dollars) { throw new BehatBehatExceptionPending(); } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function($dir) { // $dir === “test1” } );Если я исполню “ls” <?php $steps->Если(/^я исполню “(.*)”$/, function($command) { // $command === “ls” } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function($dir) { chdir(fixtures/ . $dir); } );Если я исполню “ls” <?php $steps->Если(/^я исполню “(.*)”$/, function($command) { exec($command, $output); $output = trim(implode(“n”, $output)); } );
  • ОПРЕДЕЛЕНИЯШАГОВДопустим я нахожусь в директории “test1” <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function($world, $dir) { chdir(fixtures/ . $dir); } );Если я исполню “ls” <?php $steps->Если(/^я исполню “(.*)”$/, function($world, $command) { exec($command, $output); $world->output = trim(implode(“n”, $output)); } );
  • ПРОВЕРЯЕМРЕЗУЛЬТАТЫТо я должен увидеть:
  • ПРОВЕРЯЕМРЕЗУЛЬТАТЫТо я должен увидеть: <?php $steps->То(/^я должен увидеть:$/, function($world, $string) { if ($world->output !== (string) $string) { throw new Exception(Неверный вывод); } } );
  • ПРОВЕРЯЕМРЕЗУЛЬТАТЫТо я должен увидеть: <?php $steps->То(/^я должен увидеть:$/, function($world, $string) { if ($world->output !== (string) $string) { throw new Exception(Неверный вывод); } } );То я должен увидеть: ( using PHPUnit ) <?php $steps->То(/^я должен увидеть:$/, function($world, $string) { assertEquals((string) $string, $world->output); } );
  • ОПРЕДЕЛЕНИЯШАГОВ <?php $steps->Допустим(/^я нахожусь в директории “(.*)”$/, function($world, $dir) { chdir(fixtures/ . $dir); } ); $steps->Если(/^я исполню “(.*)”$/, function($world, $command) { exec($command, $output); $world->output = trim(implode(“n”, $output)); } ); $steps->То(/^я должен увидеть:$/, function($world, $string) { assertEquals((string) $string, $world->output); } );
  • ОПРЕДЕЛЕНИЯШАГОВ <?php $steps-> Допустим(/^я нахожусь в директории “(.*)”$/, function($world, $dir) { chdir(fixtures/ . $dir); } )-> Если(/^я исполню “(.*)”$/, function($world, $command) { exec($command, $output); $world->output = trim(implode(“n”, $output)); } )-> То(/^я должен увидеть:$/, function($world, $string) { assertEquals((string) $string, $world->output); } ) ;
  • Workflow 1. Описываем поведение
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/ 3. Реализуем поведение
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/ 3. Реализуем поведение 4. Проверяем поведение
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/ 3. Реализуем поведение 4. Проверяем поведение
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/ 3. Реализуем поведение: 3.1. Пишем спеки 3.2. Прогоняем спеки 3.3. Пишем код 3.4. Прогоняем спеки 4. Проверяем поведение
  • Workflow 1. Описываем поведение 2. Проверяем поведение ( $ ) behat features/ 3. Реализуем поведение: 3.1. Пишем спеки 3.2. Прогоняем спеки 3.3. Пишем код 3.4. Прогоняем спеки 4. Проверяем поведение
  • Описание web- приложений
  • M!"#
  • Установка 1. Добавляем pear-channel: $ pear channel-discover pear.behat.org 2. Ставим: $ pear install behat/mink-beta
  • <?phpuse BehatMinkMink, BehatMinkSession, BehatMinkDriverGoutteDriver, BehatMinkDriverSahiDriver;// инициализируем Mink и сессии$mink = new Mink();$mink->registerSession(goutte, new Session(new GoutteDriver($startUrl)));$mink->registerSession(javascript,, new Session(new SahiDriver($startUrl, firefox)));// выполняем действия в стандартном драйвере$mink->getSession(goutte)->getPage()->clickLink(Downloads);echo $mink->getSession(goutte)->getPage()->getContent();// выполняем действия в javascript (Sahi) сессии$mink->getSession(javascript)->getPage()->clickLink(Downloads);echo $mink->getSession(javascript)->getPage()->getContent();
  • Новый проект 1. Создаем каркас проекта: $ cd path/to/project && zf ...
  • Новый проект 1. Создаем каркас проекта: $ cd path/to/project && zf ... Getting Started with Zend Framework By Rob Allen, www.akrabat.com Document Revision 1.7.6 Copyright © 2006, 2010
  • Новый проект 1. Создаем каркас проекта: $ cd path/to/project && zf ... 2. Инициализируем B$%&: $ behat --init
  • Новый проект 3. Знакомим B$%& с M!"#: $ vim behat.yml # behat.yml default: environment: parameters: start_url: http://tutorial.zf.dev/ imports: - mink/behat.yml $ vim features/support/bootstrap.php <?php // features/support/bootstrap.php require_once PHPUnit/Autoload.php; require_once PHPUnit/Framework/Assert/Functions.php; require_once mink/autoload.php; $ behat --steps --lang ru
  • # language: ruФункционал: Альбомы Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов Сценарий: Добавление альбома Допустим я на странице /index/add Если я ввожу "Pendulum" в поле "Artist" И я ввожу "In Silico" в поле "Title" И нажимаю "Add" То я должен видеть "In Cilico" И я должен видеть "Edit"
  • # language: ruФункционал: Альбомы Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов Сценарий: Добавление альбома Допустим я на странице /index/add Если я ввожу "Pendulum" в поле "Artist" И я ввожу "In Silico" в поле "Title" И нажимаю "Add" То я должен видеть "In Cilico" И я должен видеть "Edit"
  • # language: ruФункционал: Альбомы Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов Сценарий: Добавление альбома Допустим в базе нет альбомов И я на странице /index/add Если я ввожу "Pendulum" в поле "Artist" И я ввожу "In Silico" в поле "Title" И нажимаю "Add" То я должен видеть "In Silico" И я должен видеть "Edit"
  • <?php# features/steps/steps.php$steps->Допустим(/^в базе нет альбомов$/, function($world) { $albums = new Application_Model_DbTable_Albums(); $albums->delete(1); });<?php# features/support/bootstrap.php// Конфигурация и инициализация тестовой среды ZF
  • # language: ruФункционал: Альбомы Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов Сценарий: Добавление альбома Допустим в базе нет альбомов И я на странице /index/add Если я ввожу "Pendulum" в поле "Artist" И я ввожу "In Silico" в поле "Title" И нажимаю "Add" То я должен видеть "In Silico" И я должен видеть "Edit"
  • # language: ruФункционал: Альбомы Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов @javascript Сценарий: Добавление альбома Допустим в базе нет альбомов И я на странице /index/add Если я ввожу "Pendulum" в поле "Artist" И я ввожу "In Silico" в поле "Title" И нажимаю "Add" То я должен видеть "In Silico" И я должен видеть "Edit"
  • http://B$%&.org
  • http://github.com/behathttp://groups.google.com/behat http://knplabs.com/trainings
  • Вопросы?http://github.com/behathttp://groups.google.com/behat http://knplabs.com/trainings