AUTOMATION TESTING
An automation framework built around Behat for testing Drupal sites
Brendan MacDonald
Available on Github
https://github.com/cameronandwilding/CWTest_Behat
WHY did we make this framework?
- reusable
- generic
- simple to deploy
- automatic automation
- make testing faster
- incorporate into the CI process
- encourage team-wide testing
- enforce a standard for our tests
- future re-work of a site
WHAT's included In the framework?
- Designed to sit in your drupal project codebase
- Composer installation
- Templates for testing content types:
- .features
- contexts
- page objects
- Page Object classes approach
- Lots of custom functions inside a helper context
- Scripts to perform various jobs
- execution
- controlling drivers
- Reporting & archiving of results
COMPOSER installation
{
"name": "cw/behat_test",
"authors": [
{
"name": "Cameron and Wilding",
"email": "info@cameronandwilding.com"
}
],
"require": {
"behat/behat": "3.0.6",
"drupal/drupal-extension": "3.1.5",
"emuse/behat-html-formatter": "0.1.0",
"phpunit/phpunit": "*"
},
"autoload": {
"psr-4": {
"CWTest\\": "src/"
}
},
"bin": [
"bin/start_phantomjs_webdriver.sh",
"bin/start_selenium_server.sh",
"bin/stop_phantomjs_webdriver.sh",
"bin/stop_selenium_server.sh",
"bin/cwtest-bootstrap.sh"
]
}
Feature Context
Feature file with a 'Create Article' Scenario
Typical behat approach
@article
Scenario: Create an Article
Given I am on '/node/add/article'
And I fill in 'edit-title-0-value' with 'Article Title'
When I press 'edit-submit'
Then I should see 'Article Article Title has been created.' in the '.messages--status'
/**
* Fills in form field with specified id|name|label|value
*/
public function fillField($field, $value)
{
$field = $this->fixStepArgument($field);
$value = $this->fixStepArgument($value);
$this->getSession()->getPage()->fillField($field, $value);
}
'Create Article' scenario
Typical login scenario
@article
Scenario: Create an Article
Given I am on '/node/add/article'
And I fill in 'edit-title-0-value' with 'Article Title'
When I press 'edit-submit'
Then I should see 'Article Article Title has been created.' in the '.messages--status'
Framework behat approach
@article
Scenario: Create an Article
Given I am logged in as a user with the administrator role
And I visit the Create Article page
When I enter the following values on the Create Article page
| FIELD | VALUE |
| TITLE | Article Title <alpha_number> |
| BODY | This is the body text of the Article. |
| IMAGE | 150x350.jpg |
| ALT | ALT - 150x350.jpg |
And I press save and publish
Then I verify that the article was created successfully
'Create Article' scenario
@article
Scenario: Create an Article
Given I am logged in as a user with the administrator role
And I visit the Create Article page
...
<?php
use CWTest\Util\ArticlePage;
class ArticleContext extends PageContext {
...
<?php
class ArticlePage extends Page {
...
Article Context
Article Page
'Create Article' Scenario
framework article scenario
Article PAGE OBJECTS
class ArticlePage {
/**
* The path to the Article Content Type.
*
* @var string
*/
private $path = '/node/add/article';
/**
* Fields visble in Create and Edit mode.
*
* @var array
*/
private $fields = array(
'TITLE' => 'edit-title-0-value',
'IMAGE' => 'edit-field-image-0-upload',
);
/**
* Frames available in Create and Edit mode.
*
* @var array
*/
private $frames = array(
'BODY' => 'cke_edit-body-0-value'
);
/**
* Buttons visible in Create mode.
*
* @var array
*/
private $create_buttons = array(
'SAVE_AND_PUBLISH' => 'Save and publish',
'SAVE_AS_UNPUBLISHED' => 'Save as unpublished',
'PREVIEW' => 'Preview',
);
/**
* Buttons visible in Edit mode.
*
* @var array
*/
private $edit_buttons = array(
'REMOVE' => 'Remove',
'SAVE_AND_KEEP_PUBLISHED' => 'Save and keep published',
'SAVE_AND_UNPUBLISH' => 'Save and unpublish',
'PREVIEW' => 'Preview',
);
article PAGE CONTEXT
class ArticleContext extends PageContext {
/**
* ArticlePage instance.
*
* @var ArticlePage
*/
private $articlePage;
/**
* ArticleContext constructor.
*/
public function __construct() {
parent::__construct();
$this->articlePage = new ArticlePage();
}
/**
* @Given I visit the Create Article page
*/
public function visitCreateArticlePage() {
$this->helperContext->visitPath($this->articlePage->getPath());
}
/**
* @Given I visit the Edit Article page
*/
public function visitEditArticlePage() {
$this->helperContext->visitPath(self::getEditPath());
}
complete article title EXAMPLE
/**
* Fills in the title field.
*
* @param string $title
*/
private function fillTitleField($title) {
$this->helperContext->iFillInFieldByIDWith(
$this->articlePage->getField(self::FIELD_TITLE), $title);
}
/**
* @Given I enter the following values on the Create Article page
*/
public function iEnterTheFollowingValuesOnTheCreateArticlePage(TableNode $table) {
foreach ($table->getHash() as $key => $value) {
$field = trim($value['FIELD']);
$value = trim($value['VALUE']);
switch ($field) {
case self::FIELD_TITLE:
self::fillTitleField($value);
break;
...
Templates
Feature files for content type tests:
- validation rules
- page structure
- create, edit, delete, & view
Page object class:
- paths
- array for each object type
- getter functions
Context class:
- perform actions on the content type
Templates
helper context
<?php
/**
* @file
*/
namespace CWTest\Context;
use Drupal\DrupalExtension\Context\RawDrupalContext;
use Behat\Behat\Hook\Scope\BeforeScenarioScope;
use Behat\Behat\Hook\Scope\AfterStepScope;
use Drupal\DrupalExtension\Context\MinkContext;
use Behat\Gherkin\Node\TableNode;
use Behat\Behat\Context\SnippetAcceptingContext;
use CWTest\Exception\CWContextException;
use CWTest\Util\RandomItems;
/**
* Class HelperContext
*
* HelperContext contains supporting functions for all Behat projects.
*/
class HelperContext extends RawDrupalContext implements SnippetAcceptingContext {
...
BEHAT SCRIPT RUNNER
./run-behat.sh [tag] [profile]
./run-behat.sh article phantomjs
Script runner syntax
To run all your article tests on firefox:
To run all your article tests using phantomsjs:
./run-behat.sh article firefox
To run a specific test within the article tests on firefox:
./run-behat.sh article firefox "Verify the structure of the Create Article page"
Supporting scripts
Installation script:
- downloads selenium server
- creates directory structure for the tests and reporting
- copies template files
Tests can be run using selenium or phantomjs.
- the framework includes scripts for stopping and starting both
- these scripts are automatically triggered by the behat runner script
Reporting
HTML reports:
- Twig
- Behat2
Results folder contains:
- HTML reports
- HTML dumps
- Screenshots
Reporting
Reporting
configuration
Configuration split between 2 YML files:
behat.yml
default:
suites:
login:
paths: [ %paths.base%/features ]
filters:
tags: @login
contexts:
- CWTest\Context\LoginContext
- CWTest\Context\MyAccountContext
- CWTest\Context\PageContext
- CWTest\Context\HelperContext:
parameters:
screenshot_path: %paths.base%/../Results/Behat/screenshots
- Drupal\DrupalExtension\Context\MinkContext
- Drupal\DrupalExtension\Context\DrupalContext
...
configuration
Configuration split between 2 YML files:
behat.local.yml
default:
extensions:
Behat\MinkExtension:
base_url:
Drupal\DrupalExtension:
drupal:
drupal_root:
DEMO
incorporating feedback
Multiple versions/attempts at the framework.
Behat knowledge is a pre-requisite.
Composer set-up was not ideal.
Reporting was inadequate.
Conclusion
Future ideas!
Try it out and let us know what you think.
https://github.com/cameronandwilding/CWTest_Behat
Automation Framework build around Behat for testing Drupal sites
By Brendan MacDonald
Automation Framework build around Behat for testing Drupal sites
- 1,145