In contrast to Test Driven Development (TDD) it impacts not only development but also the specification of tasks, their testing and implementation. Since we don't want to reinvent the wheel, we will be using BLT (by Acquia) to easily set up Drupal 8 with BDD. It's fun, let’s check it out.
How does it work?
At the center, BDD is a human readable specification of a task focussing on behavior. This makes it possible for product owners and clients to guide the implementation and leave out unnecessary details. Let's describe a feature in Gherkin.
Scenario: User can see the logo on the homepage
Given I am logged in as TestUser
And I visit the homepage
Then I should see the logo
This is an example of a specification that ensures that the logo is visible on the homepage. It covers the prerequisites (Given) and the implementation (Then) with the focus of what's important to the stakeholders. Writing well-thought-out specifications is helpful to pinpoint the requirements of the client. The result is a text in plain English that is understandable to both developers and stakeholders.
In my experience, it's very important to have the team commit to specifications as the primary way of solving tasks. It takes a bit of time to learn the Gherkin syntax. But the advantages are a shared understanding of the requirements and less unnecessary clarification.
Development setup
To set up a simple Drupal application with BDD we will use blt. Check out the following page for system requirements. Run following commands to set up a Drupal 8 project.
# Create blt drupal project with composer
composer create-project --no-interaction acquia/blt-project drupal-8-bdd-project
# Navigate into project folder
cd drupal-8-bdd-project/
# Start up vm
blt vm
# SSH into the vagrant machine
vagrant ssh
# Set up local drupal project
blt setup
# Set up (only on first call) and run behat
blt tests:behat
Check out local.drupal-8-bdd-project.com to see the Drupal 8 app 🎉.
Testing - the behat way
We will now use the example specification that we created before and implement it as a behaviour driven test. We need to slightly change the definition though to reuse code. Create a file called CorporateIdentity.feature
at tests/behat/features/
.
# tests/behat/features/CorporateIdentity.feature
Feature: Corporate identity
In order to verify that users recognize the company
As a user
I should be able to see the website based on the corporate styleguide
@api
Scenario: User can see the logo on the homepage
Given I am logged in as a user with the "authenticated user" role
And I am on "/"
Then I should see the logo
The feature title and the three lines beneath give context to what the feature is about. The @api
annotation above the scenario definition is a magically defined driver in the behat configuration (tests/behat/behat.yml
). By default it uses the DrupalDriver
to bootstrap the Drupal application. The slightly adjusted scenario definition reuses the Drupal context code. Therefore we only need to implement the Then I should see the logo
definition.
Inside tests/behat/features/bootstrap/Drupal/FeatureContext.php
add the following method.
<?php
namespace Drupal;
...
public function __construct() {
}
/**
* Asserts that the logo is visible.
*
* @Then /^(?:|I )should see the logo$/
*
* @throws \Behat\Mink\Exception\ElementHtmlException
*/
public function assertLogoIsVisible() {
$this->assertSession()->elementAttributeContains(
'css',
'.site-branding__logo img',
'src',
'lightning.png'
);
}
}
The @Then
annotation accepts a regex which evaluates what function has to be run. The code uses Mink to assert the image element and the src
attribute containing the expected image. Run the following command to see the specification succesfully pass.
blt tests:behat
Conclusion
I used BDD in a few projects and it has been great to minimize unnecessary work and ensure that things work as expected. Seeing specifications pass successfully is also kinda fun and reassuring. What experiences did you have with BDD? Did they differ from mine? Looking forward to reading about it.