What is Behat? An intro to the BDD framework

To implement automated testing that improves your code and saves you time, here's how to use Behat, a Behavior Driven Development (BDD) PHP framework.
A mock unit test example

What is Behat?

To implement automated testing that improves our code and saves us time, our engineering team at Pixo uses Behat. Behat is a Behavior Driven Development (BDD) PHP framework. (If you’re thinking, what is BDD? – first check out this post on BDD from my colleague and QA analyst Jeremy Boehme.) 

Behat uses Gherkin syntax to create testable scenarios that explain the desired behavior of a system under that scenario. Here’s an example of a user story in Gherkin that can be translated into a BDD test:

Feature: Display full blog articles from an externally hosted site.
As a site visitor, I should be able to visit this site and read full blog articles. Although this website’s blog content is hosted from an external site, I should be able to browse and read posts without this being obvious (i.e., not an iframe).

 

When should you use Behat?

Behat can be used for unit tests (to test a single function), as we do for some projects at Pixo, but it’s mostly used for integration tests (how multiple functions work together) and end-to-end tests (how a user experiences the software). 

Because unit tests test a single function, they’re faster and cheaper — so it’s widely advised that unit tests should account for 70% of automated tests in your software. Automated integration tests should account for 20%, and end-to-end tests should account for 10%. The higher up on the testing pyramid, the more difficult the test is to write and implement.

 

Pyramid with three levels labeled from bottom to top unit, integration, e2e with an arrow scale indicating the bottom tests are faster and cheaper than the top levels
The testing pyramid illustrates the level of investment required for each of the three testing strategies. Source: betterprogramming.pub

When to mock test vs. test the real software

When the code path you’re trying to test has a dependency, you have the choice to mock or stub that dependency, or test that code path with the actual dependency. The terms “mock” and “stub” are often used interchangeably. Mocking or stubbing is a lot like it sounds; you are replacing certain content with an impostor or a placeholder. Depending on the context, it might even make sense to think of this as a decoy or a dummy (e.g., crash testing a car). The point is to have something that will resemble the real thing without actually needing the real thing.

Mock for unit testing

When you mock or stub it, you are doing just enough to set up your test for the exact, controlled scenario you are testing. This is to test a single unit of functionality.

An example mock from our scenario above:

Scenario: The mock source is valid
When providing a valid mock input
Then I should receive a specific output

A mock unit test example

In our PHP example

In our PHP example, we are mocking the response from the blog API based on a fixed, test input $sourceUrl. If the source we pass into the getBlogArticles method matches what we’ve defined as “valid”, we return a JSON response that mirrors what a real response from the API will look like. If it’s not “valid”, we return an error. We aren’t testing the API directly. We are testing that our system, when providing a specific input, will receive a specific output. Notice that the example doesn’t really test the business logic. It’s not from the end user’s perspective, but from the engineer’s perspective.

Test the actual dependency for integration testing

Test the actual dependency for integration testing

When you test with the actual dependency, this is an integration test. You are not only testing a single unit, but how two or more units interact with each other. Now that we can test our system’s response to specific controlled inputs, we can test how it works with the real API and how the two units work together to create a list of blog articles.

An example of testing with the real API from our scenario above:

Scenario: The real blog article source is valid
When providing a the real input
Then I should receive a specific output

With integration testing, you will need to clean out the database between scenarios so that the tests are isolated and repeatable.

Next up: Using Behat for end-to-end testing and setup for specific frameworks

Those are the Behat basics. In future posts, we’ll cover how to use Behat for end-to-end (E2E) testing and how to setup Behat for specific platforms like Drupal and Symfony.