Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Behavior & Specification Driven Development in PHP - #OpenWest

Behavior & Specification Driven Development in PHP - #OpenWest

Let's move past the basics of test driven development and into the amazing world of specification-driven development and behavior-driven development. Using the tools PHPSpec and Behat, I'll show how you can not only build test coverage but also generate much of your code for you. In this talk, we’ll see what PHPSpec & Behat can do with a series of examples and use cases.

Joshua Warren

May 09, 2015
Tweet

More Decks by Joshua Warren

Other Decks in Programming

Transcript

  1. OR:

  2. I heard you like to code, so let’s write code

    that writes code while you code.
  3. Founder & CEO Founded Creatuity in 2008 PHP Development Firm

    Focused on the Magento platform Tink, a Creatuity shareholder
  4. BDD - no, the B does not stand for beer,

    despite what a Brit might tell you Behavior Driven Development
  5. In BDD, you write feature files in the form of

    user stories that you test against.
  6. BDD uses a ubiquitous language - basically, a language that

    business stakeholders, project managers, developers and our automated tools can all understand.
  7. 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"

  8. Before you write a line of code, you write a

    specification for how that code should work
  9. Create /phpspec.yaml suites: main: namespace: App psr4_prefix: App src_path: app

    extensions: - PhpSpec\Laravel\Extension\LaravelExtension
  10. 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"
 

  11. 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
  12. /features/bootstrap/FeatureContext.php /**
 * @Given I am not logged in as

    :arg1
 */
 public function iAmNotLoggedInAs($arg1)
 {
 throw new PendingException();
 }

  13. Behat expects us to add logic to this function to

    detect the user is not logged in.
  14. 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"

  15. /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();
 }
 }

  16. /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);
 }
  17. 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
  18. These failures show us that Behat is testing our app

    properly, and now we just need to write the application logic.
  19. spec/FitbitSpec.php namespace spec;
 
 use PhpSpec\ObjectBehavior;
 use Prophecy\Argument;
 
 class

    FitbitSpec extends ObjectBehavior
 {
 function it_is_initializable()
 {
 $this->shouldHaveType('Fitbit');
 }
 }

  20. Now we add a bit more to the file so

    PHPSpec will understand what this class should do.
  21. 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)
  22. This is very powerful with frameworks like Laravel and Magento,

    which have PHPSpec plugins that help PHPSpec know where class files should be located.
  23. Fitbit.php - class Fitbit { function connect($email)
 {
 // TODO:

    write logic here
 }
 
 function sleepData($email)
 {
 // TODO: write logic here
 }

  24. We now know that our new feature is working correctly

    without needing to open a web browser
  25. The purpose of this talk is to get you hooked

    on Behat & PHPSpec and show you how easy it is to get started.
  26. PHPSpec can be used at a very granular level to

    ensure your application logic works correctly
  27. Next week, setup Behat and PHPSpec on one of your

    projects and take it for a quick test by implementing one short feature.