Slide 1

Slide 1 text

Behavior & Specification Driven Development in PHP Presented by Joshua Warren

Slide 2

Slide 2 text

OR:

Slide 3

Slide 3 text

I heard you like to code, so let’s write code that writes code while you code.

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

About Me

Slide 6

Slide 6 text

PHP Developer Working with PHP since 1999

Slide 7

Slide 7 text

Founder & CEO Founded Creatuity in 2008 PHP Development Firm Focused on the Magento platform Tink, a Creatuity shareholder

Slide 8

Slide 8 text

JoshuaWarren.com @JoshuaSWarren

Slide 9

Slide 9 text

IMPORTANT! • joind.in/14065 • Download slides • Post comments • Leave a rating!

Slide 10

Slide 10 text

What You Need To Know ASSUMPTIONS

Slide 11

Slide 11 text

Today we assume you’re a PHP developer.

Slide 12

Slide 12 text

That you are familiar with test driven development.

Slide 13

Slide 13 text

And that you’ve at least tried PHPUnit, Selenium or another testing tool.

Slide 14

Slide 14 text

BDD - no, the B does not stand for beer, despite what a Brit might tell you Behavior Driven Development

Slide 15

Slide 15 text

Think of BDD as stepping back a level from TDD.

Slide 16

Slide 16 text

Graphic thanks to BugHuntress

Slide 17

Slide 17 text

TDD generally deals with functional units.

Slide 18

Slide 18 text

BDD steps back a level to consider complete features.

Slide 19

Slide 19 text

In BDD, you write feature files in the form of user stories that you test against.

Slide 20

Slide 20 text

BDD uses a ubiquitous language - basically, a language that business stakeholders, project managers, developers and our automated tools can all understand.

Slide 21

Slide 21 text

Sample Behat Feature File Feature: Laravel Test
 In order to demonstrate Laravel and Behat
 As a user
 I need to be able to visit the homepage of a new Laravel app
 
 Scenario: Homepage
 Given I am on the homepage
 Then I should see "Laravel 5"


Slide 22

Slide 22 text

Behat

Slide 23

Slide 23 text

We implement BDD in PHP with a tool called Behat

Slide 24

Slide 24 text

Behat is a free, open source tool designed for BDD and PHP

Slide 25

Slide 25 text

behat.org

Slide 26

Slide 26 text

SpecBDD - aka, Testing Tongue Twisters Specification Behavior Driven Development

Slide 27

Slide 27 text

Before you write a line of code, you write a specification for how that code should work

Slide 28

Slide 28 text

Focuses you on architectural decisions up-front

Slide 29

Slide 29 text

PHPSpec

Slide 30

Slide 30 text

Open Source tool for specification driven development in PHP

Slide 31

Slide 31 text

www.phpspec.net

Slide 32

Slide 32 text

Why Use Behat and PHPSpec?

Slide 33

Slide 33 text

These tools allow you to focus exclusively on logic

Slide 34

Slide 34 text

Helps build functional testing coverage

Slide 35

Slide 35 text

Guides planning and ensuring that all stakeholders are in agreement

Slide 36

Slide 36 text

Let’s Build Something!

Slide 37

Slide 37 text

… what we’re building …

Slide 38

Slide 38 text

Setting up Our Project

Slide 39

Slide 39 text

Setup a Laravel 5 project

Slide 40

Slide 40 text

Run composer require —dev behat/behat behat/mink behat/mink-extensions laracasts/behat-laravel-extension phpspec/phpspec benconstable/phpspec-laravel

Slide 41

Slide 41 text

Run: vendor/bin/behat —init

Slide 42

Slide 42 text

Create /behat.yaml default:
 extensions:
 Laracasts\Behat: ~
 Behat\MinkExtension\ServiceContainer\MinkExtension:
 default_session: laravel
 laravel: ~


Slide 43

Slide 43 text

Create /phpspec.yaml suites: main: namespace: App psr4_prefix: App src_path: app extensions: - PhpSpec\Laravel\Extension\LaravelExtension

Slide 44

Slide 44 text

Features

Slide 45

Slide 45 text

features/fitbit.feature Feature: Fitbit Integration
 In order to obtain Fitbit data
 As a user
 I need to be able to authenticate with Fitbit
 Scenario: Not yet authenticated
 Given I am not logged in as “[email protected]” When I go to "/fitbit/"
 Then I should see "Please authenticate"
 


Slide 46

Slide 46 text

vendor/bin/behat —append-snippets Scenario: Not yet authenticated:6 Given I am not logged in as “[email protected] When I go to "/fitbit/" Then I should see "Please authenticate" 1 scenario (1 undefined) 3 steps (1 undefined, 2 skipped) 0m0.48s (11.00Mb) u features/bootstrap/FeatureContext.php - `I am not logged in as` definition added

Slide 47

Slide 47 text

Behat’s written code for us!

Slide 48

Slide 48 text

/features/bootstrap/FeatureContext.php /**
 * @Given I am not logged in as :arg1
 */
 public function iAmNotLoggedInAs($arg1)
 {
 throw new PendingException();
 }


Slide 49

Slide 49 text

Behat writes just enough to get us show us where to add our logic.

Slide 50

Slide 50 text

Behat expects us to add logic to this function to detect the user is not logged in.

Slide 51

Slide 51 text

Before we do that, let’s finish out our feature file.

Slide 52

Slide 52 text

features/fitbit.feature continued Scenario: I have authenticated
 Given I am logged in as “[email protected]” When I go to "/fitbit/"
 Then I should see "Welcome back"
 Scenario: I have sleep data
 Given I am logged in as “[email protected]”
 When I go to "/fitbit/sleep/"
 Then I should see "Sleep Report"


Slide 53

Slide 53 text

Run vendor/bin/behat —append-snippets one more time

Slide 54

Slide 54 text

Now, let’s fill in the logic Behat needs us to add.

Slide 55

Slide 55 text

/features/bootstrap/FeatureContext.php /**
 * @Given I am not logged in as :email
 */
 public function iAmNotLoggedInAs($email)
 {
 // We completely log out
 // Destroy the previous session
 if (Session::isStarted()) {
 Session::regenerate(true);
 } else {
 Session::start();
 }
 }


Slide 56

Slide 56 text

/features/bootstrap/FeatureContext.php public function iAmLoggedInAs($email)
 {
 // Destroy the previous session
 if (Session::isStarted()) {
 Session::regenerate(true);
 } else {
 Session::start();
 }
 
 // Login the user and since the driver and this code now
 // share a session this will also login the driver session
 $user = User::where('email', $email)->firstOrFail();
 Auth::login($user);
 
 // Save the session data to disk or to memcache
 Session::save();
 
 // Hack for Selenium
 // Before setting a cookie the browser needs to be launched
 if ($this->getSession()->getDriver() instanceof \Behat\Mink\Driver\Selenium2Driver) {
 $this->visit('login');
 }
 
 // Get the session identifier for the cookie
 $encryptedSessionId = Crypt::encrypt(Session::getId());
 $cookieName = Session::getName();
 
 // Set the cookie
 $minkSession = $this->getSession();
 $minkSession->setCookie($cookieName, $encryptedSessionId);
 }

Slide 57

Slide 57 text

We run vendor/bin/behat once more

Slide 58

Slide 58 text

vendor/bin/behat … Scenario: I have sleep data Given I am logged in as "[email protected]" When I go to "/fitbit/sleep/" Then I should see "Sleep Report" The text "Sleep Report" was not found anywhere in the text of the current page. (Behat\Mink\Exception\ResponseTextException) --- Failed scenarios: features/fitbit.feature:6 features/fitbit.feature:11 features/fitbit.feature:16

Slide 59

Slide 59 text

A perfect failure!

Slide 60

Slide 60 text

These failures show us that Behat is testing our app properly, and now we just need to write the application logic.

Slide 61

Slide 61 text

Specifications

Slide 62

Slide 62 text

Now we write specifications for how our Fitbit class should work.

Slide 63

Slide 63 text

These specifications should provide the logic to deliver the results that Behat is testing for.

Slide 64

Slide 64 text

vendor/bin/phpspec describe Fitbit Specification for Fitbit created in /spec/ FitbitSpec.php

Slide 65

Slide 65 text

PHPSpec generates a basic spec file for us

Slide 66

Slide 66 text

spec/FitbitSpec.php namespace spec;
 
 use PhpSpec\ObjectBehavior;
 use Prophecy\Argument;
 
 class FitbitSpec extends ObjectBehavior
 {
 function it_is_initializable()
 {
 $this->shouldHaveType('Fitbit');
 }
 }


Slide 67

Slide 67 text

This default spec tells PHPSpec to expect a class named Fitbit.

Slide 68

Slide 68 text

Now we add a bit more to the file so PHPSpec will understand what this class should do.

Slide 69

Slide 69 text

spec/FitbitSpec.php continued function it_connects_to_fitbit($email)
 {
 $this->connect($email)->shouldReturn('Success');
 }
 
 function it_returns_sleep_data($email)
 {
 $this->sleepData($email)->shouldReturn([8, 8, 8, 8, 8]);
 }


Slide 70

Slide 70 text

Now we run PHPSpec once more…

Slide 71

Slide 71 text

vendor/bin/phpspec run 10 ! is initializable (142ms) class Fitbit does not exist. 15 ! connects to fitbit (100ms) class Fitbit does not exist. 20 ! returns sleep data class Fitbit does not exist. ---- broken examples Fitbit 10 ! is initializable (142ms) class Fitbit does not exist. Fitbit 15 ! connects to fitbit (100ms) class Fitbit does not exist. Fitbit 20 ! returns sleep data class Fitbit does not exist. 1 specs 3 examples (3 broken)

Slide 72

Slide 72 text

Lots of failures…

Slide 73

Slide 73 text

But wait a second - PHPSpec prompts us!

Slide 74

Slide 74 text

Do you want me to create `Fitbit` for you? [Y/n]

Slide 75

Slide 75 text

PHPSpec will create the class and the methods for us!

Slide 76

Slide 76 text

This is very powerful with frameworks like Laravel and Magento, which have PHPSpec plugins that help PHPSpec know where class files should be located.

Slide 77

Slide 77 text

Fitbit.php - class Fitbit { function connect($email)
 {
 // TODO: write logic here
 }
 
 function sleepData($email)
 {
 // TODO: write logic here
 }


Slide 78

Slide 78 text

And now, the easy part…

Slide 79

Slide 79 text

Implementation

Slide 80

Slide 80 text

Implement logic in the new Fitbit class in the locations directed by PHPSpec

Slide 81

Slide 81 text

Tie that logic into views in our application.

Slide 82

Slide 82 text

Once we’re done with the implementation, we move on to…

Slide 83

Slide 83 text

Testing

Slide 84

Slide 84 text

Once we’re done, running phpspec run should return green

Slide 85

Slide 85 text

Once phpspec returns green, run behat, which should return green as well

Slide 86

Slide 86 text

We now know that our new feature is working correctly without needing to open a web browser

Slide 87

Slide 87 text

PHPSpec gives us confidence that the application logic was implemented correctly.

Slide 88

Slide 88 text

Behat gives us confidence that the feature is being displayed properly to users.

Slide 89

Slide 89 text

Success!

Slide 90

Slide 90 text

The purpose of this talk is to get you hooked on Behat & PHPSpec and show you how easy it is to get started.

Slide 91

Slide 91 text

Behat and PHPSpec are both powerful tools

Slide 92

Slide 92 text

PHPSpec can be used at a very granular level to ensure your application logic works correctly

Slide 93

Slide 93 text

Next week, setup Behat and PHPSpec on one of your projects and take it for a quick test by implementing one short feature.

Slide 94

Slide 94 text

Keep In Touch! • joind.in/14065 • @JoshuaSWarren • JoshuaWarren.com