The introduction of Behat 3, and the subsequent release of the Behat Drupal Extension 3, opened up several new features with regards to testing Drupal sites. The concept of test suites, combined with the fact that all contexts are now treated equally, means that a site can have different suites of tests that focus on specific areas of need.
Background
Behat is a PHP framework for implementing Behavior Driven Development (BDD). The aim is to use ubiquitous language to describe value for everybody involved, from the stake-holders to the developers. A quick example:
In order to encourage visitors to become more engaged in the forums Visitors who choose to post a topic or comment Will earn a 'Communicator' badge
This is a Behat feature, there need be no magic or structure to this. The goal is to simply and concisely describe a feature of the site that provides true value. In Behat, features are backed up with scenarios. Scenarios are written in Gherkin and are mapped directly to step-definitions which execute against a site, and determine if, indeed, a given scenario is working.
Continuing with the above example:
Scenario: A user posts a comment to an existing topic and earns the communicator badge Given a user is viewing a forum topic "Getting started with Behat" When they post a comment They should immediately see the "Communicator" badge
Each of the Given
, When
, and Then
steps are mapped to code using either regex, or newly in Behat 3, Turnip syntax:
/** * Create a forum topic. * * @Given a user is viewing a forum topic ":topic" */ public function assertUserViewingForumTopic($topic) { // Create and log in user. $user = (object) ['name' => $this->getRandom()->name()]; $this->userCreate($user); // Create a forum topic titled $topic. // ... }
While that may look like a lot of custom code, extensions – such as the Mink Extension and the Drupal Extension – provide many pre-built step-definitions and methods for interacting with websites and the Drupal backend. Much has been written about using these extensions, so let’s now move on to some exciting new features available in Behat 3.
Test Suites
Continuing with our example above, one can imagine there are many ways to assert that behavior. In the brief PHP code example, a user is programmatically created. However, the same scenario could also test that a 'register' link exists on the forum comment, and manually create a user through the UI. Of course, such a test would be rather slow (although still valuable to prevent front-end regressions). Behat 3 provides a way to use the same scenario with different backend contexts for evaluating whether the scenario is currently functional. These are called test suites.
Test suites can have different contexts loaded and be tied to different tags:
default: suites: frontend: contexts: - FrontEndContext filters: tags: "frontend" backend: contexts: - ApiContext filters: tags: "backend"
This defines two suites, 'frontend', and 'backend'. The filter specifies that any scenario tagged with @frontend
will be executed by the frontend suite and similarly @backend
will be run by the backend suite. Our example scenario above could be tagged with both:
@frontend @backend Scenario: A user posts a comment to an existing topic and earns the communicator badge ...
When the front-end suite is run, the FrontEndContext
class will be used and that could contain all the logic necessary to assert that the frontend is behaving as this scenario expects. When the backend suite is run, the ApiContext
will be used and that could test the low-level badge functionality needed to support the frontend. Since these tests will be faster, they could be run much more frequently should test execution time start to bottleneck the project.
No More Singular Context
Unlike Behat 2, there is no more singular context. One or more contexts can be specified for each suite. The only constraint is that no two contexts being used at the same time may provide the same step definition. Thus, in our example, the FrontEndContext
and the ApiContext
are mutually exclusive, since they both provide the same step-definitions.
The Drupal Extension provides a nice example of splitting out step-definitions into multiple contexts that can be used together as needed:
default: suites: default: contexts: - FeatureContext - Drupal\DrupalExtension\Context\DrupalContext - Drupal\DrupalExtension\Context\MessageContext - Drupal\DrupalExtension\Context\MinkContext - Drupal\DrupalExtension\Context\MarkupContext
If, for instance, a particular suite doesn't touch the API, then the DrupalContext
could be removed from the above example.
This allows for much more specific contexts that can be used as needed, rather than overwhelming test writers with every possible available step-definition.
Removing Barriers to Testing
If all of this seems like a lot of effort to expend on any given project, remove the work needed to get started!
By using a starting kit for projects that provide a Behat framework, and even some simple starting tests, new tests can quickly be added even if the project isn't strictly following BDD principles. Ideally, during the course of the project, new, more specific tests are added and the default generic tests are edited or removed completely.