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

Behat v3! Behavioral-Driven-Development, Functi...

Avatar for weaverryan weaverryan
November 21, 2014

Behat v3! Behavioral-Driven-Development, Functional Tests and Selenium

Testing our applications is something we all do. Ahem, rather, it’s something we all *wish* we did. In this chat, I’ll introduce you to Behat (version 3!!!!): a behavior-driven-development (BDD) library that allows you to write functional tests against your application just by writing human-readable sentences/scenarios.

To sweeten the deal these tests can be run in a real browser (via Selenium2) with just the flip of a switch. If you asked me to develop without Behat, I’d just retire. It’s that sweet. By the end, you’ll have everything you need to start functionally-testing with Behat in your new, or very old and ugly project.

Avatar for weaverryan

weaverryan

November 21, 2014
Tweet

More Decks by weaverryan

Other Decks in Technology

Transcript

  1. KnpUniversity.com github.com/weaverryan • Lead for the Symfony documentation ! •

    KnpLabs US - Symfony consulting, training, 
 Kumbaya ! • Writer for KnpUniversity.com screencasts Who is this Hipster? ! ! ! ! ! ! • Husband of the much more talented @leannapelham
  2. KnpUniversity.com github.com/weaverryan • Lead for the Symfony documentation ! •

    KnpLabs US - Symfony consulting, training, 
 Kumbaya ! • Writer for KnpUniversity.com screencasts Who is this Hipster? ! ! ! ! ! ! • Husband of the much more talented @leannapelham My friend Konstantin (@everzet)… ! who actually wrote Behat ! (yay Konstantin!)
  3. I've just dreamt up this cool new feature that we

    should implement! ! Why? Because it's cool! “
  4. @weaverryan Solution 1. Define business value for the features
 2.

    Prioritize features by their business value
 3. Describe them with readable scenarios
 4. And only then - implement them
  5. Feature: {custom_title} In order to {A} As a {B} I

    need to {C} • {A} - the benefit or value of the feature • {B} - the role (or person) who will benefit • {C} - short feature description | The person “writing” this feature - the “I”
  6. @weaverryan Solution 1. Define ! 2. Prioritize ! 3. Describe

    ! 4. And only then - 1. Define business value for the features
  7. Feature: I18n In order to read news in french As

    a french user I need to be able to switch locale read news in French @weaverryan
  8. Feature: I18n In order to read news in french As

    a french user I need to be able to switch locale read news in French The business value @weaverryan
  9. Feature: I18n In order to read news in french As

    a french user I need to be able to switch locale read news in French The person who benefits + The “author” of this feature @weaverryan
  10. Feature: I18n In order to read news in french As

    a french user I need to be able to switch locale read news in French Description of the feature, the action the person will take @weaverryan
  11. @weaverryan Solution 1. Define ! 2. Prioritize ! 3. Describe

    ! 4. And only then - 2. Prioritize features by their business value
  12. @weaverryan 1. Define ! 2. Prioritize ! 3. Describe !

    4. And only then - Solution 3. Describe them with readable scenarios
  13. Feature: News admin panel In order to maintain a list

    of news As a site administrator I need to be able to edit news Scenario: Add new article Given I am on the "/admin/news" page When I click "New Article" And I fill in "Title" with "Learned BDD" And I press "Save" Then I should see "A new article was added"
  14. Scenarios Given ! Defines the initial state of the system

    for the scenario Scenario: Add new article Given I am on the "/admin/news" page When I click "New Article" And I fill in "Title" with "Learned BDD" And I press "Save" Then I should see "A new article was added"
  15. Scenarios When ! Describes the action taken by the person/role

    Scenario: Add new article Given I am on the "/admin/news" page When I click "New Article" And I fill in "Title" with "Learned BDD" And I press "Save" Then I should see "A new article was added"
  16. Scenarios Then ! Describes the observable system state after the

    action has been performed Scenario: Add new article Given I am on the "/admin/news" page When I click "New Article" And I fill in "Title" with "Learned BDD" And I press "Save" Then I should see "A new article was added"
  17. Scenarios And/But ! Can be added to create multiple Given/When/Then

    lines Scenario: Add new article Given I am on the "/admin/news" page When I click "New Article" And I fill in "Title" with "Learned BDD" And I press "Save" Then I should see "A new article was added"
  18. Example #2 Scenario: List available articles Given there are 5

    news articles And I am on the "/admin" page When I click "News Administration" Then I should see 5 news articles
  19. @weaverryan What is Behat? Behat does one simple thing: **

    each line in a scenario is called a “step” Behat “executes” your scenarios, reading each step and calling the function associated with it It Maps Each step** to a PHP Callback
  20. Installing Behat Behat is just a library that can be

    installed easily in any project via Composer Friends that are new to Composer? Free screencast: KnpUniversity.com/composer
  21. In your project directory... 1) Download Composer $> curl -s

    http://getcomposer.org/installer | php 2) Let Composer do all the work composer require behat/behat!
  22. @weaverryan To use Behat in a project you need: !

    ! 1) Actual *.feature files to be executed
 2) A FeatureContext.php file that holds the PHP callbacks for each step
 3) (optional) A behat.yml configuration file
  23. <?php // features/bootstrap/FeatureContext.php
 
 use Behat\Behat\Context\SnippetAcceptingContext;
 use Behat\Gherkin\Node\PyStringNode;
 use Behat\Gherkin\Node\TableNode;


    
 /**
 * Behat context class.
 */
 class FeatureContext implements SnippetAcceptingContext
 {
 }
 Nothing Interesting here yet...
  24. 1) Describe your Feature Feature: ls features/ls.feature In order to

    see the directory structure As a UNIX user I need to be able to list the current directory's contents
  25. 2) Your First Scenario If you have two files in

    a directory, and you're running the command - you should see them listed. “
  26. Scenario: List 2 files in a directory Write in the

    natural voice of “a UNIX user” Given I have a file named "foo" And I have a file named "bar" When I run "ls" Then I should see "foo" in the output And I should see "bar" in the output features/ls.feature
  27. Matching is done with simple wildcards For each step that

    doesn’t have a matching method, Behat prints code to copy into FeatureContext
  28. class FeatureContext extends BehatContext { /** @Given I have a

    file named :file */
 public function iHaveAFileNamed($file)
 {
 throw new PendingException();
 }
 
 /** @When I run :command */
 public function iRun($command)
 {
 throw new PendingException();
 } // ... } 4) Copy in the new Definitions Quoted text maps to a method argument
  29. /** * @Given I have a file named :file */

    public function iHaveAFileNamed($file) { touch($file); } ! /** * @Given I have a directory named :dir */ public function iHaveADirectoryNamed($dir) { mkdir($dir); }
  30. /** * @When I run :command */ public function iRun($command)

    { exec($command, $output); $this->output = trim(implode("\n", $output)); } ! /** * @Then I should see :string in the output */ public function iShouldSeeInTheOutput($string) { if (strpos($this->output, $string) === false) { throw new \Exception(‘Did not see’.$string); ); }
  31. Scenario Step Definition Given I have a file named “foo”

    pattern public function iHaveAFileNamed($file) { do work Pass/Fail: Each step is a “test”, which passes *unless* an exception is thrown touch($file); @Given I have a file named :file What Behat *does*
  32. but wouldn’t it be really cool to command a browser,

    fill out forms and check the output?
  33. Mink! http://mink.behat.org/ • A standalone library to use PHP to

    
 command a “browser”
 • One easy API that can be used to 
 command Selenium, Goutte, ZombieJS, etc @weaverryan
  34. use Behat\Mink\Driver\GoutteDriver; use Behat\Mink\Session; ! // change *only* this line

    to run // in Selenium, etc $driver = new GoutteDriver(); $session = new Session($driver);
  35. $page = $session->getPage(); // drill down into the page $ele

    = $page->find('css', 'li:nth-child(4) a'); echo 'Link text is: '.$ele->getText(); echo 'href is: '.$ele->getAttribute('href'); // click the link // (you can also fill out forms) $ele->click();
  36. http://mink.behat.org/ @weaverryan Behat Mink Integration MinkExtension • An “Extension” is

    like a Behat plugin
 • The MinkExtension makes using Mink 
 inside Behat a matter of configuration
  37. @weaverryan Install Mink & MinkExtension $> php composer.phar update •

    Update composer.json to include > Mink > MinkExtension > Goutte and Selenium2 Drivers for Mink http://bit.ly/behat-mink-composer
 • Update the vendor libraries
  38. @weaverryan Bootstrap MinkExtension behat.yml is the Behat configuration file and

    can contain much more than you see here # behat.yml
 default:
 extensions:
 Behat\MinkExtension:
 goutte: ~
 selenium2: ~
 # The base URL you're testing
 base_url: http://en.wikipedia.org/ http://bit.ly/behat-yml
  39. @weaverryan Extend MinkContext use Behat\MinkExtension\Context\RawMinkContext;
 
 /**
 * Behat context

    class.
 */
 class FeatureContext extends RawMinkContext Extending RawMinkContext gives us...
  40. Access to a Mink Session class FeatureContext extends RawMinkContext {

    public function doSomething() { $session = $this->getSession(); $session->visit('http://behat.org'); } ! // ... } OMG! Our custom definitions can now command a browser!
  41. @weaverryan More! Add MinkContext # behat.yml
 default:
 extensions: # ...

    suites:
 default:
 contexts:
 - FeatureContext
 - Behat\MinkExtension\Context\MinkContext
 Behat now parses definitions from *our* class *and* this MinkContext class
  42. We inherit a pile of great definitions the -dl option

    prints all current definitions Before adding MinkContext:
  43. In other words: We can write some tests for our

    app without writing any PHP code
  44. # features/wikipedia.feature Feature: Search In order to see a word

    definition As a website user I need to be able to search for a word These 4 definitions all come packaged with MinkContext Scenario: Searching for a page that does exist Given I am on "/wiki/Main_Page" When I fill in "search" with "Behavior Driven Development" And I press "searchButton" Then I should see "agile software development"
  45. # features/wikipedia.feature Scenario: Searching for a page with autocompletion Given

    I am on "/wiki/Main_Page" When I fill in "search" with "Behavior Driv" Then I should see "Behavior Driven Development"
  46. Add @javascript # ... ! @javascript Scenario: Searching for a

    page with autocompletion Given I am on "/wiki/Main_Page" When I fill in "search" with "Behavior Driv" Then I should see "Behavior Driven Development” ! ! !
  47. Add @javascript # ... ! @javascript Scenario: Searching for a

    page with autocompletion Given I am on "/wiki/Main_Page" When I fill in "search" with "Behavior Driv" Then I should see "Behavior Driven Development” ! ! ! Yep, that’s all you do!
  48. Yes, thank you Ryan, your office smells of many leather

    bound books and rich mahogany. ! But, what aren’t you telling us?
  49. ... and learn more about what you can do with

    Mink: http://mink.behat.org/ 2) Write features for your app!