On Github aczietlow / behat
Chris Zietlow \ @aczietlow
your team should decide what the code quality means to you.
Case studies conducted at Microsoft and IBM indicate that teams that adopt TDD experience 40% to 90% bugs, which results in 15-35% additional development time.
"Imperfect tests, run frequently, are much better than perfect tests that are never written at all." - Martin Fowler
Behat is a BDD (Behavior Driven Development) framework written in PHP
There's the module for that, because of course there is
Drupal ExtensionComposer.json
"require": { "behat/behat": "3.0.*@stable", "drupal/drupal-extension": "3.0.*@dev" }
Behat.yml
default: suites: default: contexts: - FeatureContext - Drupal\DrupalExtension\Context\DrupalContext extensions: Behat\MinkExtension:Use your google powers
I want to be able to log into my website in order to edit my content.
As a an anonymous user, I want to be able to log into my website, So that I can edit my content.3 lines that describe the role, the feature, and the benefit
What does it mean to be logged in? How do we know that we are logged in?
Given I am an anonymous user When I am at "user/login" And I fill in "name" with "admin" And I fill in "pass" with "admin" And press "Log in" Then I should see the link "Log out"Given [some context] When [some event] Then [outcome]
How do we check can edit content.
Given I am logged in as a user with the administrator role When I am at "node/add/page" Then I should see "Create Basic page" And I should get a 200 HTTP response
Slap it in a feature file and boom you have your test.
#./features/user_login.feature @api Feature: User Login. As a an anonymous user, I want to be able to log into my website, So that I can edit my content. Scenario: I can log in. Given I am an anonymous user When I am at "user/login" And I fill in "name" with "admin" And I fill in "pass" with "admin" And press "Log in" Then I should see the link "Log out" Scenario: I can edit content Given I am logged in as a user with the administrator role When I am at "node/add/page" Then I should see "Create Basic page" And I should get a 200 HTTP response
Tests are saved in .feature files
$ bin/behat features/user_login.feature
@api Feature: Basic page nodes As a admin user I want to have the ability to create basic page nodes So that I can populate the site with content. Scenario: I have permission to create a basic page Given I am logged in as a user with the administrator role Then I should see the text "Log out" When I visit "node/add/page" Then I should get a 200 HTTP response And I should see "Create Basic page" Scenario: Newly created page nodes appear on the homepage. Given "page" content: | title | body | author | | Page Content | This is my body field | admin | When I go to the homepage Then I should see "Page Content"
@api Feature: Content Type Event As an anonymous user I want to view data related to an Event So that I can decide it is something I would like to attend. Scenario: Add an event node and verify that the necessary fields exist. Given I am an anonymous user And an "Event Terms" term with the name "camp" And an "Event Terms" term with the name "drupal" And "event" content: | title | field_event_location | field_event_date | field_event_tags | status | | Atlanta Drupal Camp | Atlanta | 2015-04-11 9:00:00 | camp, drupal | 1 | When I am at "content/atlanta-drupal-camp" Then I should see the text "Atlanta Drupal Camp" And I should see the text "Atlanta" And I should see the text "Saturday, April 11, 2015" And I should see the text "camp" And I should see the text "drupal"
Tests should return the site back to the state it was in before the test run.
/** * Remove any created nodes. * * @AfterScenario */ public function cleanNodes() { // Remove any nodes that were created. foreach ($this->nodes as $node) { $this->getDriver()->nodeDelete($node); } }
Each scenario step maps to a function that performs the step
Given I am an anonymous user
/** * @Given I am an anonymous user * @Given I am not logged in */ public function assertAnonymousUser() { // Verify the user is logged out. if ($this->loggedIn()) { $this->logout(); }
Out of the box the Mink and Drupal Drivers will provide a lot of step definitions that you can use.
$ behat -dl
default | When I visit the login page default | Given I am an anonymous user default | Given I am not logged in default | Given I am logged in as a user with the :role role(s) default | Given I am logged in as a user with the :role role(s) and I have the following fields: default | Given I am logged in as :name default | Given I am logged in as a user with the :permissions permission(s) default | Then I should see (the text ):text in the ":rowText" row default | Given I click :link in the :rowText row
Feature: Migrations As an editor of the website I want the workbench module enabled So that I can create custom editing work flows Scenario: Confirm the workbench module is installed Given the "workbench" module is installed
Custom step definitions go in features/bootstrap/FeatureContext.php
//features/bootstrap/FeatureContext.php use Drupal\DrupalExtension\Context\RawDrupalContext; use Behat\Behat\Context\SnippetAcceptingContext; use Behat\Gherkin\Node\PyStringNode; use Behat\Gherkin\Node\TableNode; /** * Defines application features from the specific context. */ class FeatureContext extends RawDrupalContext implements SnippetAcceptingContext { }
/** * Asserts that a given module exists and is enabled. * * @Given the :module module is installed */ public function assertModuleExists($module) { if (module_exists($module)) { return TRUE; } $message = sprintf('Module "%s" is not installed.', $module); throw new \Exception($message); }By extending the drupal extension we get access to a bootstrapped drupal as well as any methods they've already defined, like nodeCreate() and login()
Then "events" migration is complete$/
/** * Asserts the given migration is complete. * * @Then /^the "([^"]*)" migration is complete$/ * * @throws /Exception if the migration did not complete. */ public function assertMigrationIsComplete($name) { $migration = Migration::getInstance($name); if ($migration->isComplete()) { return TRUE; } $message = sprintf('The "%s" migration is not complete.', $name); throw new \Exception($message); }
We use Mink to interact with the browser
Some common usages of the Mink API
$element = $session->getPage(); $element->findAll($selector, $locator); $element->getText(); $element->getHtml(); $element->isVisible(); $element->click(); $element->press(); $element->check(); $element->uncheck();Mink Cheat Sheet
- tests are awesome - tests are good for you, the client, and the product
- Behat Documentation - Behat in a box - No More Excuses - Follow me on twitter: @aczietlow