bdd в php с behat и mink

Post on 10-May-2015

5.942 Views

Category:

Technology

9 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

BDD в php

Яктотакой

everzetsenior from-birth web

developer в

@

Яктотакой

senior from-birth web developer в

International speakerРазработчик Behat, MinkРазработчик jade.phpРазработчик capifonyCore-contributor Symfony2 frameworkРазработчик плагинов symfony и Symfony2

everzet@knplabs.com

http://github.com/everzethttp://card.everzet.com

everzet@

BDD, Symfony2 эксперты

Активные контрибуторы в open-source проекты

Консультанты, аудиторы, тренеры

http://knplabs.com

Историятестирования

UnitTest

История

Автом

атизаци

я тестов

UnitTest TDD

Тесты

вперед

История

Автом

атизаци

я тестов

UnitTest TDD

Dan N

orth

BDD

История

Тесты

вперед

Автом

атизаци

я тестов

BDD ⎯ эволюция TDD

- Эволюция-хренолюция... Что не так с TDD?

Test-Driven Development

Test-Driven Development

Мы на самом деле говорим о тестах???Но каким образом тестировать то, чего еще нет?

Test-Driven Development

дизайнеНа самом деле, мы говорим о

Test-Driven DevelopmentBehavior

© 2003, Dan North

BDD был создан как наборконвенций поверхTDD

Тест-кейсы должы составлять предложения

BDD был создан как наборконвенций поверхTDD

testFindsCustomerById()testFailsForDuplicateCustomers()

testFindsCustomerById()testFailsForDuplicateCustomers()

Тест-кейсы должны начинаться со слова “should”shouldFindCustomerById()shouldFailForDuplicateCustomers()

BDD был создан как наборконвенций поверхTDD

Тест-кейсы должы составлять предложения

shouldFindCustomerById()shouldFailForDuplicateCustomers()

Класс тест-кейсов должен представлять из себя существительное для кейсов

class CustomerTableTest extends \PHPUnitTestCase{ /** * @Test */ shouldFindCustomerById() ...}

BDD был создан как наборконвенций поверхTDD

Тест-кейсы должны начинаться со слова “should”

Тест-кейсы должы составлять предложенияtestFindsCustomerById()testFailsForDuplicateCustomers()

АССЕРШЕНЫтоже TEST-ориентированы

assertEquals($expected, $actual)

assertGreaterThan($expected, $actual)

assertInstanceOf($class, $actual)

АССЕРШЕНЫтоже TEST-ориентированы

ТЕСТируем

assertEquals($expected, $actual)

assertGreaterThan($expected, $actual)

assertInstanceOf($class, $actual)

$actual should be Equals to $expected

$actual should be GreaterThan $expected

$actual should be InstanceOf $class

Описываем

АССЕРШЕНЫтоже TEST-ориентированы

ТЕСТируем

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.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

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

Пишем СПЕЦИФИКАЦИЮ, а не UnitTEST

UnitTest TDD

Spec BDDСначала дизайн

Dan N

orth

BDD

История

Тесты

вперед

Автом

атизаци

я тестов

photo by dsearlsphoto by Horia Varlan

СЛОВАРЬ

photo by dsearlsphoto by Horia Varlan

для те

стеро

в

СЛОВАРЬ

photo by dsearlsphoto by Horia Varlan

для аналитиков

СЛОВАРЬ

для те

стеро

в

photo by dsearlsphoto by Horia Varlan

для де

вело

перо

в СЛОВАРЬ для аналитиков

для те

стеро

в

photo by dsearlsphoto by Horia Varlan

для заказчиков

СЛОВАРЬ

для де

вело

перо

в для аналитиков

для те

стеро

в

photo by dsearlsphoto by Horia Varlan

1СЛОВАРЬ

для заказчиков

для де

вело

перо

в для аналитиков

для те

стеро

в

photo by dsearlsphoto by Horia Varlan

тестер

ы

аналитики

девелоперызаказчики

ИСКОРЕНИТ множество проблемДИЗАЙНА и КОММУНИКАЦИЙ

1СЛОВАРЬ

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

photo by joshfassbind.com

In order to [A]As a [B]I need [C]

Наратив:

Чтобы [A]В качестве [B]Мне нужно [C]

Наратив:

A ⎯ добавочное знач. (профит) функционала B ⎯ профитирующая персона (роль)C ⎯ функционал

Чтобы [A]В качестве [B]Мне нужно [C]

Наратив:

⎯ Сила данной конструкции в том, что она требует определения профита от функционала еще до его реализации

© Dan North

A ⎯ добавочное знач. (профит) функционала B ⎯ профитирующая персона (роль)C ⎯ функционал

Чтобы [A]В качестве [B]Мне нужно [C]

Наратив:

Поведение story ⎯ это ее приемочный критерий!⎯ если система удовлетворяет все приемочные критерии, то она работает верно; если не выполняет - неверно.

In order to ...As a ...I need ...

Story:

Given some initial context (the givens),When an event occurs,Then ensure some outcomes.

In order to ...As a ...I need ...

Story:

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:

Scenario 2:

Story:

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.

In order to ...As a ...I need ...

UnitTest TDD

Spec BDD

Scenario BDD

Сначал

а анализ

Dan N

orth

BDD

История

Сначала дизайн

Тесты

вперед

Автом

атизаци

я тестов

Сначал

а анализ

Сначала дизайн

UnitTest TDD

Spec BDD

Scenario BDD

Dan N

orth

BDD

История

Тесты

вперед

Автом

атизаци

я тестов

+

Given some initial context (the givens),When an event occurs,Then ensure some outcomes.

In order to ...As a ...I need ...

Given some initial context (the givens),When an event occurs,Then ensure some outcomes.

Scenario 1:

Scenario 2:

Story:

Given some initial context (the givens),When an event occurs,Then ensure some outcomes.

In order to ...As a ...I need ...

Given some initial context (the givens),When an event occurs,Then ensure some outcomes.

Scenario: 1st scenario title

Scenario: 2nd scenario title

Feature: Feature description

1. feature2.

sce

nario

3. step......

2. s

cena

rio

3. step......

Given some initial context (the givens)When an event occursThen ensure some outcomes

In order to ...As a ...I need ...

Given some initial context (the givens)When an event occursThen ensure some outcomes

Scenario: 1st scenario title

Scenario: 2nd scenario title

Feature: Feature descriptionfeature tree

Given some initial context (the givens)When an event occursThen ensure some outcomes

In order to ...As a ...I need ...

Given some initial context (the givens)When an event occursThen ensure some outcomes

Scenario: 1st scenario title

Scenario: 2nd scenario title

Feature: Feature description

Etant donné some initial context (the givens)Lorsque an event occursAlors ensure some outcomes

In order to ...As a ...I need ...

Etant donné some initial context (the givens)Lorsque an event occursAlors ensure some outcomes

Scénario: 1st scenario title

Scénario: 2nd scenario title

Fonctionnalité: Feature description# language: fr

ならば some initial context (the givens)しかし an event occurs前提 ensure some outcomes

In order to ...As a ...I need ...

ならば some initial context (the givens)しかし an event occurs前提 ensure some outcomes

シナリオ: 1st scenario title

シナリオ: 2nd scenario title

フィーチャ: Feature description# language: ja

Допустим some initial context (the givens)Когда an event occursТо ensure some outcomes

In order to ...As a ...I need ...

Допустим some initial context (the givens)Когда an event occursТо ensure some outcomes

Сценарий: 1st scenario title

Сценарий: 2nd scenario title

Функционал: Feature description# language: ru

Let go and haul some initial context (the givens)Blimey! an event occursAye ensure some outcomes

In order to ...As a ...I need ...

Let go and haul some initial context (the givens)Blimey! an event occursAye ensure some outcomes

Heave to: 1st scenario title

Heave to: 2nd scenario title

Ahoy matey!: Feature description# language: en-pirate

Let go and haul some initial context (the givens)Blimey! an event occursAye ensure some outcomes

Let go and haul some initial context (the givens)Blimey! an event occursAye ensure some outcomes

Heave to:

Heave to:

Ahoy matey!:# language: en-pirate

Приемочные критериидолжны быть исполняемы!

Установка

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Я должен иметь утилиту листинга директорий

Сценарий: 2 файла в директории

Чтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий

# language: ruФункционал: Утилита ls

Допустим я нахожусь в директории “test1”Если я исполню “ls”То я должен увидеть:

Сценарий: 2 файла в директории

Чтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий

# language: ruФункционал: Утилита ls

""" file_one.txt file_foo.txt """

1. feature2.

sce

nario

Допустим я нахожусь в директории “test1”Если я исполню “ls”То я должен увидеть:

Сценарий: 2 файла в директории

Чтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий

# language: ruФункционал: Утилита ls

""" file_one.txt file_foo.txt """

Допустим я нахожусь в директории “test1”Если я исполню “ls”То я должен увидеть:

Сценарий: 2 файла в директории

Чтобы узнать содержимое директорииКак пользователь UNIXЯ должен иметь утилиту листинга директорий

# language: ruФункционал: Утилита ls

""" file_one.txt file_foo.txt """

Допустим я нахожусь в директории “test1”

ОПРЕДЕЛЕНИЯШАГОВ

<?php

Допустим('/^я нахожусь в директории “(.*)”$/');

ОПРЕДЕЛЕНИЯШАГОВ

Допустим я нахожусь в директории “test1”

<?php

Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

ОПРЕДЕЛЕНИЯШАГОВ

Допустим я нахожусь в директории “test1”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

ОПРЕДЕЛЕНИЯШАГОВ

Допустим я нахожусь в директории “test1”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

???

ОПРЕДЕЛЕНИЯШАГОВ

Допустим я нахожусь в директории “test1”

ТИПЫРЕЗУЛЬТАТОВШАГОВ

ТИПЫРЕЗУЛЬТАТОВШАГОВ

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

2. Undefined шаг ⎯ у которого нет (не найдено) определений

ТИПЫРЕЗУЛЬТАТОВШАГОВ

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

2. Undefined шаг ⎯ у которого нет (не найдено) определений

3. Ambiguous шаг ⎯ который подпадает под несколько определений

ТИПЫРЕЗУЛЬТАТОВШАГОВ

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

2. Undefined шаг ⎯ у которого нет (не найдено) определений

3. Ambiguous шаг ⎯ который подпадает под несколько определений

4. Failed шаг ⎯ который throw \Exception();

ТИПЫРЕЗУЛЬТАТОВШАГОВ

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

2. Undefined шаг ⎯ у которого нет (не найдено) определений

3. Ambiguous шаг ⎯ который подпадает под несколько определений

4. Failed шаг ⎯ который throw \Exception();

5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии

ТИПЫРЕЗУЛЬТАТОВШАГОВ

1. Pending шаг ⎯ который throw new \Behat\Behat\Exception\Pending();

2. Undefined шаг ⎯ у которого нет (не найдено) определений

3. Ambiguous шаг ⎯ который подпадает под несколько определений

4. Failed шаг ⎯ который throw \Exception();

5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии

6. Passed шаг ⎯ который не кидает эксепшенов

ТИПЫРЕЗУЛЬТАТОВШАГОВ

ОПРЕДЕЛЕНИЯШАГОВ

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

Допустим я нахожусь в директории “test1”

ОПРЕДЕЛЕНИЯШАГОВ

Если я исполню “ls”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

Допустим я нахожусь в директории “test1”

<?php

$steps->Если('/^я исполню “(.*)”$/', function($dollars) { throw new \Behat\Behat\Exception\Pending(); });

ОПРЕДЕЛЕНИЯШАГОВ

Если я исполню “ls”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function() { throw new \Behat\Behat\Exception\Pending(); });

Допустим я нахожусь в директории “test1”

<?php

$steps->Если('/^я исполню “(.*)”$/', function($command) { // $command === “ls” });

ОПРЕДЕЛЕНИЯШАГОВ

Если я исполню “ls”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function($dir) { // $dir === “test1” });

Допустим я нахожусь в директории “test1”

<?php

$steps->Если('/^я исполню “(.*)”$/', function($command) { exec($command, $output); $output = trim(implode(“\n”, $output)); });

ОПРЕДЕЛЕНИЯШАГОВ

Если я исполню “ls”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function($dir) { chdir('fixtures/' . $dir); });

Допустим я нахожусь в директории “test1”

<?php

$steps->Если('/^я исполню “(.*)”$/', function($world, $command) { exec($command, $output); $world->output = trim(implode(“\n”, $output)); });

ОПРЕДЕЛЕНИЯШАГОВ

Если я исполню “ls”

<?php

$steps->Допустим('/^я нахожусь в директории “(.*)”$/', function($world, $dir) { chdir('fixtures/' . $dir); });

Допустим я нахожусь в директории “test1”

ПРОВЕРЯЕМРЕЗУЛЬТАТЫ

То я должен увидеть:

<?php

$steps->То('/^я должен увидеть:$/', function($world, $string) { if ($world->output !== (string) $string) { throw new \Exception('Неверный вывод'); } });

ПРОВЕРЯЕМРЕЗУЛЬТАТЫ

То я должен увидеть:

<?php

$steps->То('/^я должен увидеть:$/', function($world, $string) { assertEquals((string) $string, $world->output); });

usingPHPUnit

<?php

$steps->То('/^я должен увидеть:$/', function($world, $string) { if ($world->output !== (string) $string) { throw new \Exception('Неверный вывод'); } });

ПРОВЕРЯЕМРЕЗУЛЬТАТЫ

То я должен увидеть:

То я должен увидеть: ( )

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

ОПРЕДЕЛЕНИЯШАГОВ

1. Описываем поведение

Workflow

$ behat features/

1. Описываем поведение2. Проверяем поведение ( )

Workflow

$ behat features/

1. Описываем поведение2. Проверяем поведение ( )3. Реализуем поведение

Workflow

$ behat features/

1. Описываем поведение2. Проверяем поведение ( )

4. Проверяем поведение3. Реализуем поведение

Workflow

$ behat features/

1. Описываем поведение2. Проверяем поведение ( )

4. Проверяем поведение3. Реализуем поведение

Workflow

3.1. Пишем спеки

$ behat features/

1. Описываем поведение2. Проверяем поведение ( )

3.4. Прогоняем спеки3.3. Пишем код3.2. Прогоняем спеки

4. Проверяем поведение

3. Реализуем поведение:

Workflow

3.1. Пишем спеки

$ behat features/

1. Описываем поведение

3.4. Прогоняем спеки3.3. Пишем код3.2. Прогоняем спеки

3. Реализуем поведение:2. Проверяем поведение ( )

4. Проверяем поведение

Workflow

Описание web-приложений

M!"#

Установка

1. Добавляем pear-channel:$ pear channel-discover pear.behat.org

2. Ставим:$ pear install behat/mink-beta

<?php

use Behat\Mink\Mink, Behat\Mink\Session, Behat\Mink\Driver\GoutteDriver, Behat\Mink\Driver\SahiDriver;

// инициализируем 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.comDocument Revision 1.7.6Copyright © 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

Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов

Сценарий: Добавление альбомаДопустим я на странице /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"

# language: ruФункционал: Альбомы

<?php# features/support/bootstrap.php

// Конфигурация и инициализация тестовой среды ZF

<?php# features/steps/steps.php$steps->Допустим('/^в базе нет альбомов$/', function($world) { $albums = new Application_Model_DbTable_Albums(); $albums->delete(1); });

Чтобы иметь представление об исполнителях Как каталогизатор Я должен уметь управлять коллекцией альбомов

Сценарий: Добавление альбомаДопустим в базе нет альбомовИ я на странице /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"

# language: ruФункционал: Альбомы

http://B$%&'.org

Вопросы?

http://github.com/behat

http://knplabs.com/trainingshttp://groups.google.com/behat

top related