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

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

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.

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!