Slide 1

Slide 1 text

BDDwith Symfony2

Slide 2

Slide 2 text

I who am everzet senior from-birth PHP developer at

Slide 3

Slide 3 text

UnitTest Test code automatically TIMELINE

Slide 4

Slide 4 text

UnitTest TDD Test code automatically Write tests first TIMELINE

Slide 5

Slide 5 text

UnitTest TDD Test code automatically Write tests first TIMELINE Dan North BDD

Slide 6

Slide 6 text

BDD ♮ evolution of TDD

Slide 7

Slide 7 text

- Oh, man, i hate evolutions! What’s wrong with TDD?

Slide 8

Slide 8 text

Test-Driven Development - Oh, man, i hate evolutions! What’s wrong with TDD?

Slide 9

Slide 9 text

Test-Driven Development Are we really talking about tests??? But how to test something, that not exists yet? - Oh, man, i hate evolutions! What’s wrong with TDD?

Slide 10

Slide 10 text

Test-Driven Development software design In reality, we’re talking bout - Oh, man, i hate evolutions! What’s wrong with TDD?

Slide 11

Slide 11 text

Test-Driven Development Behavior © 2003, Dan North

Slide 12

Slide 12 text

BDDwas introduced as set of conventions over TDD

Slide 13

Slide 13 text

BDDwas introduced as set of conventions over TDD Test method names should be sentences testFindsCustomerById() testFailsForDuplicateCustomers() tests, that class finds customer by ID tests, that class fails for dup customers

Slide 14

Slide 14 text

BDDwas introduced as set of conventions over TDD Test method names should be sentences testFindsCustomerById() testFailsForDuplicateCustomers() Test method names should start with “should” word shouldFindCustomerById() shouldFailForDuplicateCustomers() tests, that class finds customer by ID tests, that class fails for dup customers class should find customer by ID class should fail for dup customers

Slide 15

Slide 15 text

BDDwas introduced as set of conventions over TDD Test method names should be sentences testFindsCustomerById() testFailsForDuplicateCustomers() Test method names should start with “should” word shouldFindCustomerById() shouldFailForDuplicateCustomers() tests, that class finds customer by ID tests, that class fails for dup customers class should find customer by ID class should fail for dup customers TestCase class should be nouns in test method sentences class CustomerTableTest extends \PHPUnitTestCase { /** * @Test */ shouldFindCustomerById() ... } CustomerTable should find customer by ID

Slide 16

Slide 16 text

ASSERTIONS are TEST-oriented too assertEquals($expected, $actual) assertGreaterThan($expected, $actual) assertInstanceOf($class, $actual) TESTing

Slide 17

Slide 17 text

ASSERTIONS are TEST-oriented too 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 TESTing Describing

Slide 18

Slide 18 text

UnitTest TDD Test code automatically Write tests first Spec BDD Design first TIMELINE Dan North BDD

Slide 19

Slide 19 text

Specification-oriented BDD Frameworks

Slide 20

Slide 20 text

*Spec RSpec by Dave Astels

Slide 21

Slide 21 text

*Spec RSpec by Dave Astels JSpec by TJ Holowaychuk

Slide 22

Slide 22 text

*Spec RSpec by Dave Astels JSpec by TJ Holowaychuk Fabulous by Alex Rudakov

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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 SPECIFICATION Write class , not UnitTEST

Slide 25

Slide 25 text

BDD SCENARIO ORIENTED photo by dsearls

Slide 26

Slide 26 text

VOCABULARY photo by dsearls photo by Horia Varlan

Slide 27

Slide 27 text

VOCABULARY photo by dsearls photo by Horia Varlan for testers

Slide 28

Slide 28 text

VOCABULARY photo by dsearls photo by Horia Varlan for testers for analysts

Slide 29

Slide 29 text

VOCABULARY photo by dsearls photo by Horia Varlan for testers for analysts for developers

Slide 30

Slide 30 text

VOCABULARY photo by dsearls photo by Horia Varlan for testers for analysts for developers for business

Slide 31

Slide 31 text

VOCABULARY photo by dsearls photo by Horia Varlan for testers for analysts for developers for business 1

Slide 32

Slide 32 text

VOCABULARY photo by dsearls photo by Horia Varlan testers analysts developers business ELIMINATING some of the AMBIGUITY and MISCOMMUNICATION

Slide 33

Slide 33 text

COMMUNICATIONS photo by joshfassbind.com

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

A the benefit or value of the feature B the person (or role) who will benefit C some feature Story: In order to [A] As a [B] I need [C]

Slide 36

Slide 36 text

Its strength is that it forces you to identify the value of delivering a story when you first define it. © Dan North Story: In order to [A] As a [B] I need [C] A the benefit or value of the feature B the person (or role) who will benefit C some feature

Slide 37

Slide 37 text

A story’s behaviour is simply its acceptance criteria! if the system fulfills all the acceptance criteria, it’s behaving correctly; if it doesn’t, it isn’t. Story:

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

Given some initial context (the givens), When an event occurs, Then ensure some outcomes. In order to ... As a ... I need ... Story:

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

UnitTest TDD Test code automatically Write tests first Spec BDD Design first Scenario BDD Analyse first TIMELINE Dan North BDD

Slide 43

Slide 43 text

GHERKINDSL photo by isobel.gordon

Slide 44

Slide 44 text

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:

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

Etant donné some initial context (the givens) Lorsque an event occurs Alors ensure some outcomes In order to ... As a ... I need ... Etant donné some initial context (the givens) Lorsque an event occurs Alors ensure some outcomes Scénario: 1st scenario title Scénario: 2nd scenario title Fonctionnalité: Feature description # language: fr

Slide 47

Slide 47 text

ͳΒ͹ 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

Slide 48

Slide 48 text

Допустим 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

Slide 49

Slide 49 text

Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes In order to ... As a ... I need ... Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes Heave to: 1st scenario title Heave to: 2nd scenario title Ahoy matey!: Feature description # language: en-pirate

Slide 50

Slide 50 text

Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes Let go and haul some initial context (the givens) Blimey! an event occurs Aye ensure some outcomes Heave to: Heave to: Ahoy matey!: # language: en-pirate

Slide 51

Slide 51 text

Acceptance criteria should be executable!

Slide 52

Slide 52 text

No content

Slide 53

Slide 53 text

In order to ... As a ... I need ... Scenario: 1st scenario title Scenario: 2nd scenario title Feature: Feature description 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

Slide 54

Slide 54 text

1. feature 2. scenario 3. step ... ... 2. scenario 3. step ... ... 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 feature tree

Slide 55

Slide 55 text

DEFINITIONS Given I have a bank account STEP

Slide 56

Slide 56 text

DEFINITIONS Given I have a bank account STEP

Slide 57

Slide 57 text

DEFINITIONS STEP

Slide 58

Slide 58 text

DEFINITIONS STEP Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } ); Given I have a bank account

Slide 59

Slide 59 text

DEFINITIONS STEP Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } ); ??? Given I have a bank account

Slide 60

Slide 60 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending();

Slide 61

Slide 61 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending(); 2. Undefined step that have no definitions (found)

Slide 62

Slide 62 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending(); 2. Undefined step that have no definitions (found) 3. Ambiguous step which match multiple definitions

Slide 63

Slide 63 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending(); 2. Undefined step that have no definitions (found) 3. Ambiguous step which match multiple definitions 4. Failed step that throw \Exception();

Slide 64

Slide 64 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending(); 2. Undefined step that have no definitions (found) 3. Ambiguous step which match multiple definitions 4. Failed step that throw \Exception(); 5. Skipped step that follows pending/undefined/failed

Slide 65

Slide 65 text

RESULT STEP TYPES 1. Pending step that throw new \Behat\Behat\Exception\Pending(); 2. Undefined step that have no definitions (found) 3. Ambiguous step which match multiple definitions 4. Failed step that throw \Exception(); 5. Skipped step that follows pending/undefined/failed 6. Passed step that doesn’t throw exceptions

Slide 66

Slide 66 text

DEFINITIONS Given I have a bank account STEP Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } );

Slide 67

Slide 67 text

DEFINITIONS Given I have a bank account STEP Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } ); When I deposit 35$

Slide 68

Slide 68 text

DEFINITIONS STEP When('/^I deposit (\d+)\$$/', function($dollars) { // $dollars === 35 } ); Given I have a bank account Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } ); When I deposit 35$

Slide 69

Slide 69 text

DEFINITIONS STEP When('/^I deposit (\d+)\$$/', function($dollars) { // $dollars === 35 } ); Given I have a bank account Given('/^I have a bank account$/', function() { throw new \Behat\Behat\Exception\Pending(); } ); When I deposit 35$

Slide 70

Slide 70 text

DEFINITIONS STEP Given('/^I have a bank account$/', function($world) { throw new \Behat\Behat\Exception\Pending(); } ); When('/^I deposit (\d+)\$$/', function($world, $dollars) { // $dollars === 35 } ); Given I have a bank account When I deposit 35$

Slide 71

Slide 71 text

DEFINITIONS STEP Given('/^I have a bank account$/', function($world) { $world->account = new BankAccount(); } ); When('/^I deposit (\d+)\$$/', function($world, $dollars) { $world->account->deposit($dollars); } ); Given I have a bank account When I deposit 35$

Slide 72

Slide 72 text

OUTCOME Then I should have 35$ TESTING

Slide 73

Slide 73 text

OUTCOME Then I should have 35$ TESTING Then('/^I should have (\d+)\$$/', function($world, $balance) { if ($balance !== $world->account->getBalance()) { throw new \Exception('Wrong balance!'); } } );

Slide 74

Slide 74 text

OUTCOME TESTING Then I should have 35$ ( ) Then('/^I should have (\d+)\$$/', function($world, $balance) { assertEquals($balance, $world->account->getBalance()); } ); using PHPUnit Then I should have 35$ Then('/^I should have (\d+)\$$/', function($world, $balance) { if ($balance !== $world->account->getBalance()) { throw new \Exception('Wrong balance!'); } } );

Slide 75

Slide 75 text

DEFINITIONS STEP Given('/^I have a bank account$/', function($world) { $world->account = new BankAccount(); } ); $steps->When('/^I deposit (\d+)\$$/', function($world, $dollars) { $world->account->deposit($dollars); } ); $steps->Then('/^I should have (\d+)\$$/', function($world, $balance) { assertEquals($balance, $world->account->getBalance()); } );

Slide 76

Slide 76 text

DEFINITIONS STEP Given('/^I have a bank account$/', function($world) { $world->account = new BankAccount(); } )-> When('/^I deposit (\d+)\$$/', function($world, $dollars) { $world->account->deposit($dollars); } )-> Then('/^I should have (\d+)\$$/', function($world, $balance) { assertEquals($balance, $world->account->getBalance()); } );

Slide 77

Slide 77 text

BehatBundle

Slide 78

Slide 78 text

USAGE BehatBundle 1. Install: http://symfony2bundles.org/Behat/BehatBundle

Slide 79

Slide 79 text

USAGE BehatBundle 1. Install: 2. Setup: $ app/console behat:test:bundle --init Application\\HelloBundle . ᵋᴷᴷ src/Application/HelloBundle/Tests/Features ᵓᴷᴷ steps ᴹ ᵋᴷᴷ steps.php ᵋᴷᴷ support ᵓᴷᴷ bootstrap.php ᵋᴷᴷ env.php write and put your features here place step definition files here example step definition file place support scripts here bootstrap environment (context) initialization http://symfony2bundles.org/Behat/BehatBundle

Slide 80

Slide 80 text

USAGE BehatBundle 1. Install: 2. Setup: $ app/console behat:test:bundle --init Application\\HelloBundle . ᵋᴷᴷ src/Application/HelloBundle/Tests/Features ᵓᴷᴷ steps ᴹ ᵋᴷᴷ steps.php ᵋᴷᴷ support ᵓᴷᴷ bootstrap.php ᵋᴷᴷ env.php write and put your features here place step definition files here example step definition file place support scripts here bootstrap environment (context) initialization 3. Colorize: $ app/console behat:test:bundle Application\\HelloBundle http://symfony2bundles.org/Behat/BehatBundle

Slide 81

Slide 81 text

BUNDLEDSteps

Slide 82

Slide 82 text

BUNDLEDSteps Browser Steps Given /^I am on(?: the)? (.*)$/ When /^I go to(?: the)? (.*)$/ When /^I (?:follow|click)(?: the)? "([^"]*)"(?: link)*$/ When /^I go back$/ When /^I go forward$/ When /^I send (POST|PUT|DELETE) to (.*) with:$/ When /^I follow redirect$/

Slide 83

Slide 83 text

BUNDLEDSteps Browser Steps Given /^I am on(?: the)? (.*)$/ When /^I go to(?: the)? (.*)$/ When /^I (?:follow|click)(?: the)? "([^"]*)"(?: link)*$/ When /^I go back$/ When /^I go forward$/ When /^I send (POST|PUT|DELETE) to (.*) with:$/ When /^I follow redirect$/ Form Steps When /^I fill in "([^"]*)" with "([^"]*)"$/ When /^I select "([^"]*)" from "([^"]*)"$/ When /^I uncheck "([^"]*)"$/ When /^I uncheck "([^"]*)"$/ When /^I attach the file at "([^"]*)" to "([^"]*)"$/ When /^I press "([^"]*)" in (.*) form$/

Slide 84

Slide 84 text

BUNDLEDSteps Request Steps Then /^Request method is (.*)$/ Then /^Request has cookie "([^"]*)"$/ Then /^Request has not cookie "([^"]*)"$/ Then /^Request cookie "([^"]*)" is "([^"]*)"$/

Slide 85

Slide 85 text

BUNDLEDSteps Request Steps Then /^Request method is (.*)$/ Then /^Request has cookie "([^"]*)"$/ Then /^Request has not cookie "([^"]*)"$/ Then /^Request cookie "([^"]*)" is "([^"]*)"$/ Response Steps Then /^Response status code is (\d+)$/ Then /^I should see "([^"]*)"$/ Then /^I should not see "([^"]*)"$/ Then /^I should see element "([^"]*)"$/ Then /^Header "([^"]*)" is set to "([^"]*)"$/ Then /^Header "([^"]*)" is not set to "([^"]*)"$/ Then /^I was redirected$/ Then /^I was not redirected$/ Then /^Print output$/

Slide 86

Slide 86 text

Feature: User logins

Slide 87

Slide 87 text

In order to have extended abilities As a site user I need to be able to login Feature: User logins

Slide 88

Slide 88 text

In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Feature: User logins

Slide 89

Slide 89 text

In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Scenario: Non-existing user can’t login Feature: User logins

Slide 90

Slide 90 text

Given a site have “everzet” user with “qwerty” password And I am on the “/login” When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given a site have “everzet” user with “qwerty” password And I am on the “/login” When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login Feature: User logins

Slide 91

Slide 91 text

Given a site have “everzet” user with “qwerty” password And I am on the “/login” When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given a site have “everzet” user with “qwerty” password And I am on the “/login” When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login Feature: User logins

Slide 92

Slide 92 text

Given I am on the “/login” page When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given I am on the “/login” page When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login Feature: User logins

Slide 93

Slide 93 text

Given I am on the “/login” page When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given a site have “everzet” user with “qwerty” password Background: Given I am on the “/login” page When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login Feature: User logins

Slide 94

Slide 94 text

Given I am on the “/login” page When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given a site have users: Background: Given I am on the “/login” page When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login | username | password | | everzet | qwerty | Feature: User logins

Slide 95

Slide 95 text

Given I am on the “/login” page When I fill in “username” with “everzet” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Welcome, everzet” In order to have extended abilities As a site user I need to be able to login Scenario: Existing user can login Given a site have users: Background: Given I am on the “/login” page When I fill in “username” with “someone” And I fill in “password” with “qwerty” And I press “login” in login form Then I should see “Login or password is incorrect” Scenario: Non-existing user can’t login | username | password | | everzet | qwerty | Feature: User logins

Slide 96

Slide 96 text

Given I am on the “/login” page When I fill in “username” with “” And I fill in “password” with “” And I press “login” in login form Then I should see “” In order to have extended abilities As a site user I need to be able to login Scenario Outline: Only existing users can login Given a site have users: Background: | username | password | | everzet | qwerty | Feature: User logins

Slide 97

Slide 97 text

Given I am on the “/login” page When I fill in “username” with “” And I fill in “password” with “” And I press “login” in login form Then I should see “” In order to have extended abilities As a site user I need to be able to login Scenario Outline: Only existing users can login Given a site have users: Background: | username | password | | everzet | qwerty | Examples: Feature: User logins

Slide 98

Slide 98 text

Given I am on the “/login” page When I fill in “username” with “” And I fill in “password” with “” And I press “login” in login form Then I should see “” In order to have extended abilities As a site user I need to be able to login Scenario Outline: Only existing users can login Feature: User logins Given a site have users: Background: | username | password | | everzet | qwerty | Examples: | username | password | message | | everzet | qwerty | Welcome, everzet | | someone | pa$$word | Login or password is incorrect |

Slide 99

Slide 99 text

USAGE 1. Colorize: $ app/console behat:test:bundle Application\\HelloBundle

Slide 100

Slide 100 text

USAGE 1. Colorize: 2. Write missing steps: Given('/^a site have users:$/', function($world, $table) { $em = $world->getClient()-> getKernel()-> getContainer()-> get('doctrine.orm.entity_manager'); // remove all users from test db with EntityManager foreach ($table->getRowHash() as $row) { // persist new user into test db with EntityManager // $row[‘username’] AND $row[‘password’] } $em->flush(); }); $ app/console behat:test:bundle Application\\HelloBundle

Slide 101

Slide 101 text

http://Behat.org One more thing

Slide 102

Slide 102 text

In-browser testing and other frameworks support

Slide 103

Slide 103 text

Sahi

Slide 104

Slide 104 text

Sahi Goutte

Slide 105

Slide 105 text

Sahi Goutte Selenium

Slide 106

Slide 106 text

Sahi Goutte Selenium sfBrowser

Slide 107

Slide 107 text

Sahi Goutte Selenium sfBrowser Symfony2 Client

Slide 108

Slide 108 text

Sahi Goutte Selenium sfBrowser Symfony2 Client through one clean API

Slide 109

Slide 109 text

M!"#

Slide 110

Slide 110 text

createClient(); $driver = new Mink\Driver\Symfony2ClientDriver($client); $session = new Mink\Session($driver); $session->visit('/hello/Fabien'); $page = $session->getPage(); $this->assertTrue($page->hasContent('Hello Fabien')); } public function testIndexWithSahi() { $driver = new Mink\Driver\SahiDriver('SAHI_SESSION_ID'); $session = new Mink\Session($driver); $session->visit('/hello/Fabien'); $page = $session->getPage(); $this->assertTrue($page->hasContent('Hello Fabien')); } }

Slide 111

Slide 111 text

createClient(); $driver = new Mink\Driver\Symfony2ClientDriver($client); $session = new Mink\Session($driver); $session->visit('/hello/Fabien'); $page = $session->getPage(); $this->assertTrue($page->hasContent('Hello Fabien')); } public function testIndexWithSahi() { $driver = new Mink\Driver\SahiDriver('SAHI_SESSION_ID'); $session = new Mink\Session($driver); $session->visit('/hello/Fabien'); $page = $session->getPage(); $this->assertTrue($page->hasContent('Hello Fabien')); } }

Slide 112

Slide 112 text

Given I am on the “/login” page When I fill in “username” with “” And I fill in “password” with “” And I press “login” in login form Then I should see “” In order to have extended abilities As a site user I need to be able to login Scenario Outline: Only existing users can login Feature: User logins Given a site have users: Background: | username | password | | everzet | qwerty | Examples: | username | password | message | | everzet | qwerty | Welcome, everzet | | someone | pa$$word | Login or password is incorrect |

Slide 113

Slide 113 text

Given I am on the “/login” page When I fill in “username” with “” And I fill in “password” with “” And I press “login” in login form Then I should see “” In order to have extended abilities As a site user I need to be able to login Scenario Outline: Only existing users can login Feature: User logins Given a site have users: Background: | username | password | | everzet | qwerty | Examples: | username | password | message | | everzet | qwerty | Welcome, everzet | | someone | pa$$word | Login or password is incorrect | @javascript

Slide 114

Slide 114 text

http://Behat.org Questions? http://joind.in/2769