2. Я
кто
такой
@ everzet
senior from-birth web
developer в
3. Я
кто
такой
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 в
16. BDD был создан как набор
конвенций поверх TDD
Тест-кейсы должы составлять предложения
testFindsCustomerById()
testFailsForDuplicateCustomers()
17. BDD был создан как набор
конвенций поверх TDD
Тест-кейсы должы составлять предложения
testFindsCustomerById()
testFailsForDuplicateCustomers()
Тест-кейсы должны начинаться со слова “should”
shouldFindCustomerById()
shouldFailForDuplicateCustomers()
18. BDD был создан как набор
конвенций поверх TDD
Тест-кейсы должы составлять предложения
testFindsCustomerById()
testFailsForDuplicateCustomers()
Тест-кейсы должны начинаться со слова “should”
shouldFindCustomerById()
shouldFailForDuplicateCustomers()
Класс тест-кейсов должен представлять из себя существительное для кейсов
class CustomerTableTest extends PHPUnitTestCase
{
/**
* @Test
*/
shouldFindCustomerById()
...
}
21. АССЕРШЕНЫ
тоже TEST-ориентированы
ТЕСТируем Описываем
assertEquals($expected, $actual) $actual should be Equals to $expected
assertGreaterThan($expected, $actual) $actual should be GreaterThan $expected
assertInstanceOf($class, $actual) $actual should be InstanceOf $class
24. *Spec
RSpec by Dave Astels
JSpec by TJ Holowaychuk
25. *Spec
RSpec by Dave Astels
JSpec by TJ Holowaychuk
Fabulous by Alex Rudakov
26. 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
27. 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
28. История
Сначала дизайн Spec BDD
UnitTest TDD BDD
Тесты вперед
Автоматизация тестов
Dan North
42. Поведение story ⎯
это ее приемочный
критерий!
⎯ если система удовлетворяет все
приемочные критерии, то она работает
верно; если не выполняет - неверно.
44. Story:
In order to ...
As a ...
I need ...
Given some initial context (the givens),
When an event occurs,
Then ensure some outcomes.
45. 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.
46. 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.
47. История
Сначала дизайн Spec BDD
UnitTest TDD BDD Scenario BDD
Сначала анализ
Тесты вперед
Автоматизация тестов
Dan North
48. История
Сначала дизайн Spec BDD
+
UnitTest TDD BDD Scenario BDD
Сначала анализ
Тесты вперед
Автоматизация тестов
Dan North
50. 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.
51. Feature: Feature description
In 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.
52. feature tree
Feature: Feature description 1. feature
In order to ...
As a ...
I need ...
Scenario: 1st scenario title
2. scenario
Given some initial context (the givens) 3. step
When an event occurs ...
Then ensure some outcomes ...
Scenario: 2nd scenario title
2. scenario
Given some initial context (the givens) 3. step
When an event occurs ...
Then ensure some outcomes ...
53. Feature: Feature description
In 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
54. # language: fr
Fonctionnalité: Feature description
In 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
55. # language: ja
: Feature description
In 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
56. # language: ru
Функционал: Feature description
In 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
57. # language: en-pirate
Ahoy matey!: Feature description
In 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
58. # language: en-pirate
Ahoy 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
62. Установка
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
63. # language: ru
Функционал: Утилита ls
Чтобы узнать содержимое директории
Как пользователь UNIX
Я должен иметь утилиту листинга директорий
64. # language: ru
Функционал: Утилита ls
Чтобы узнать содержимое директории
Как пользователь UNIX
Я должен иметь утилиту листинга директорий
Сценарий: 2 файла в директории
65. # language: ru
Функционал: Утилита ls
Чтобы узнать содержимое директории
Как пользователь UNIX
Я должен иметь утилиту листинга директорий
Сценарий: 2 файла в директории
Допустим я нахожусь в директории “test1”
Если я исполню “ls”
То я должен увидеть:
"""
file_one.txt
file_foo.txt
"""
66. # language: ru 1. feature
Функционал: Утилита ls
Чтобы узнать содержимое директории
Как пользователь UNIX
Я должен иметь утилиту листинга директорий
Сценарий: 2 файла в директории
Допустим я нахожусь в директории “test1”
2. scenario
Если я исполню “ls”
То я должен увидеть:
"""
file_one.txt
file_foo.txt
"""
67. # language: ru
Функционал: Утилита ls
Чтобы узнать содержимое директории
Как пользователь UNIX
Я должен иметь утилиту листинга директорий
Сценарий: 2 файла в директории
Допустим я нахожусь в директории “test1”
Если я исполню “ls”
То я должен увидеть:
"""
file_one.txt
file_foo.txt
"""
75. ТИПЫРЕЗУЛЬТАТОВШАГОВ
1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
2. Undefined шаг ⎯ у которого нет (не найдено) определений
76. ТИПЫРЕЗУЛЬТАТОВШАГОВ
1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
2. Undefined шаг ⎯ у которого нет (не найдено) определений
3. Ambiguous шаг ⎯ который подпадает под несколько определений
77. ТИПЫРЕЗУЛЬТАТОВШАГОВ
1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
2. Undefined шаг ⎯ у которого нет (не найдено) определений
3. Ambiguous шаг ⎯ который подпадает под несколько определений
4. Failed шаг ⎯ который throw Exception();
78. ТИПЫРЕЗУЛЬТАТОВШАГОВ
1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
2. Undefined шаг ⎯ у которого нет (не найдено) определений
3. Ambiguous шаг ⎯ который подпадает под несколько определений
4. Failed шаг ⎯ который throw Exception();
5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии
79. ТИПЫРЕЗУЛЬТАТОВШАГОВ
1. Pending шаг ⎯ который throw new BehatBehatExceptionPending();
2. Undefined шаг ⎯ у которого нет (не найдено) определений
3. Ambiguous шаг ⎯ который подпадает под несколько определений
4. Failed шаг ⎯ который throw Exception();
5. Skipped шаг ⎯ который идет следом за pending/undefined/failed в сценарии
6. Passed шаг ⎯ который не кидает эксепшенов
80. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function() {
throw new BehatBehatExceptionPending();
}
);
81. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function() {
throw new BehatBehatExceptionPending();
}
);
Если я исполню “ls”
82. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function() {
throw new BehatBehatExceptionPending();
}
);
Если я исполню “ls”
<?php
$steps->Если('/^я исполню “(.*)”$/',
function($dollars) {
throw new BehatBehatExceptionPending();
}
);
83. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function($dir) {
// $dir === “test1”
}
);
Если я исполню “ls”
<?php
$steps->Если('/^я исполню “(.*)”$/',
function($command) {
// $command === “ls”
}
);
84. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function($dir) {
chdir('fixtures/' . $dir);
}
);
Если я исполню “ls”
<?php
$steps->Если('/^я исполню “(.*)”$/',
function($command) {
exec($command, $output);
$output = trim(implode(“n”, $output));
}
);
85. ОПРЕДЕЛЕНИЯШАГОВ
Допустим я нахожусь в директории “test1”
<?php
$steps->Допустим('/^я нахожусь в директории “(.*)”$/',
function($world, $dir) {
chdir('fixtures/' . $dir);
}
);
Если я исполню “ls”
<?php
$steps->Если('/^я исполню “(.*)”$/',
function($world, $command) {
exec($command, $output);
$world->output = trim(implode(“n”, $output));
}
);
87. ПРОВЕРЯЕМРЕЗУЛЬТАТЫ
То я должен увидеть:
<?php
$steps->То('/^я должен увидеть:$/',
function($world, $string) {
if ($world->output !== (string) $string) {
throw new Exception('Неверный вывод');
}
}
);
88. ПРОВЕРЯЕМРЕЗУЛЬТАТЫ
То я должен увидеть:
<?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);
}
);
106. Новый проект
1. Создаем каркас проекта:
$ cd path/to/project && zf ...
2. Инициализируем B$%&':
$ behat --init
107. Новый проект
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
108. # language: ru
Функционал: Альбомы
Чтобы иметь представление об исполнителях
Как каталогизатор
Я должен уметь управлять коллекцией альбомов
Сценарий: Добавление альбома
Допустим я на странице /index/add
Если я ввожу "Pendulum" в поле "Artist"
И я ввожу "In Silico" в поле "Title"
И нажимаю "Add"
То я должен видеть "In Cilico"
И я должен видеть "Edit"
109.
110. # language: ru
Функционал: Альбомы
Чтобы иметь представление об исполнителях
Как каталогизатор
Я должен уметь управлять коллекцией альбомов
Сценарий: Добавление альбома
Допустим я на странице /index/add
Если я ввожу "Pendulum" в поле "Artist"
И я ввожу "In Silico" в поле "Title"
И нажимаю "Add"
То я должен видеть "In Cilico"
И я должен видеть "Edit"
111.
112.
113. # language: ru
Функционал: Альбомы
Чтобы иметь представление об исполнителях
Как каталогизатор
Я должен уметь управлять коллекцией альбомов
Сценарий: Добавление альбома
Допустим в базе нет альбомов
И я на странице /index/add
Если я ввожу "Pendulum" в поле "Artist"
И я ввожу "In Silico" в поле "Title"
И нажимаю "Add"
То я должен видеть "In Silico"
И я должен видеть "Edit"
114.
115. <?php
# features/steps/steps.php
$steps->Допустим('/^в базе нет альбомов$/',
function($world) {
$albums = new Application_Model_DbTable_Albums();
$albums->delete(1);
}
);
<?php
# features/support/bootstrap.php
// Конфигурация и инициализация тестовой среды ZF
116. # language: ru
Функционал: Альбомы
Чтобы иметь представление об исполнителях
Как каталогизатор
Я должен уметь управлять коллекцией альбомов
Сценарий: Добавление альбома
Допустим в базе нет альбомов
И я на странице /index/add
Если я ввожу "Pendulum" в поле "Artist"
И я ввожу "In Silico" в поле "Title"
И нажимаю "Add"
То я должен видеть "In Silico"
И я должен видеть "Edit"
117. # language: ru
Функционал: Альбомы
Чтобы иметь представление об исполнителях
Как каталогизатор
Я должен уметь управлять коллекцией альбомов
@javascript
Сценарий: Добавление альбома
Допустим в базе нет альбомов
И я на странице /index/add
Если я ввожу "Pendulum" в поле "Artist"
И я ввожу "In Silico" в поле "Title"
И нажимаю "Add"
То я должен видеть "In Silico"
И я должен видеть "Edit"