fromJune 2015
Column:

Testing 1.2.3...

Exploring the New Features in Behat 3
0

 Alphabet Stencil 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.

Image: ©http://www.istockphoto.com/profile/shork