On Github csarrazi-slides / starting-with-behat
Created by Charles Sarrazin / @csarrazi
Create a single vocabulary and process for planning, implementing and testing a feature, with a focus on the behavior of the feature.
A structured language to describe a feature
Feature: {custom_title} In order to {A} As a {B} I need to {C}
Feature: I18n In order to read news in french As a french user I need to be able to switch locale
1) Feature: News admin panel 2) Feature: I18n 3) Feature: News list API
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"
Defines the initial state of the system for the scenario
Describes the action taken with the person / role
Describes the observable system state after the action has been performed
Can be added to create multiple Given/When/Then lines
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
gives us a consistent language for describing features and their scenarios...
Having a standard way of describing features is cool...
... executing those sentences as functional tests is just awesome
Behat does one simple thing:
It maps each step** to a PHP Callback
Behat "executes" your scenarios, reading each step and calling the function associated with it
**: each line in a scenario is called a "step"
Behat is just a library that can be installed easily in any project using Composer
composer require "behat/behat"
And... That's it!
The most important product of the installation is an executable bin/behat file
To use Behat in a project, you need:
Actual *.feature files to be executed A FeatureContext.php file that holds the PHP callbacks for each step (optional) A behat.yml configuration file<php use Behat\Behat\Context\Context; use Behat\Behat\Context\SnippetAcceptingContext; use Behat\Gherkin\Node\PyStringNode; use Behat\Gherkin\Node\TableNode; class FeatureContext implements Context, SnippetAcceptingContext { /** * Initializes context. * * Every scenario gets its own context instance. * You can also pass arbitrary arguments to the * context constructor through behat.yml. */ public function __construct() { } }
Testing the "ls" command
Feature: ls In order to see the directory structure As a UNIX user I need to be able to list the current directory's contents
Scenario: List 2 files in a directory 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
$ php bin/behat
/** * @Given I have a file named :arg1 */ public function iHaveAFileNamed($arg1) { throw new PendingException(); } /** * @When I run :arg1 */ public function iRun($arg1) { throw new PendingException(); } /** * @Then I should see :arg1 in the output */ public function iShouldSeeInTheOutput($arg1) { throw new PendingException(); }
/** * @Given I have a file named :file */ public function iHaveAFileNamed($file) { touch($file); } /** * @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) { \PHPUnit_Framework_Assert::assertContains($string, explode("\n", $this->output)); }
Pass / Fail: Each step is a "test", which passes *unless* an exception is thrown
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);
// visit a page $session->visit('http://behat.org'); echo'URL : '.$session->getCurrentUrl(); echo'Status: '.$session->getStatusCode();
$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();
Behat ← MinkExtension →Mink
$ php composer update
{ "require-dev": { "behat/behat": "^3.0", "behat/mink": "^1.7", "behat/mink-extension": "^2.1", "behat/mink-goutte-driver": "^1.2", "behat/mink-selenium2-driver": "^1.3" }, "config": { "bin-dir": "bin/" } }
# behat.yml default: extensions: Behat\MinkExtension: goutte: ~ selenium2: ~ # The base URL to app you're testing base_url: http://en.wikipedia.org/
behat.yml is the Behat configuration file and can contain much more than you see here
use Behat\MinkExtension\Context\MinkContext; class FeatureContext extends MinkContext
Extending MinkContext gives us 2 things...
class FeatureContext extends MinkContext { public function doSomething() { $session = $this->getSession(); $session->visit('http://behat.org'); } // ... }
Our custom definitions can now command a browser!
Before extending MinkContext:
The -dl option prints all available definitions
After extending MinkContext:
We can write some tests for our app without writing any PHP code
# 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 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"
These 4 definitions are bundled with MinkContext
Feature: Search In order to see a word definition As a website user I need to be able to search for a word @javascript 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"
You simply need to tag the test using @javascript
$ wget http://selenium-release.storage.googleapis.com/2.53/selenium-server-standalone-2.53.0.jar $ java -jar selenium-server-standalone-2.53.0.jar