Advertisement
PHP

BDD With Behat

by

The BDD PHP framework Behat, allows you to test your PHP applications using human-readable sentences to write features and scenarios about how your applications should behave in order to test out its functionality. We can then run these tests to see if our application is behaving as expected. Let's spend about 15 minutes quickly going over Behat's installation process and learn how we can test our PHP applications behavior using the basics.


Installation

To begin testing with Behat, we just need to install it on our local development machine. I'll be using Composer, but you can take a look at a the documentation for additional installation methods.

Within your PHP application (I have a blank PHP app named phpbehat created in advance) create a composer.json file with the following code to load in Behat:

{
	"require": {
		"behat/behat": "2.4.*@stable"
	},
	"minimum-stability": "dev",
	"config": {
		"bin-dir": "bin/"
	}
}

In your terminal we can install it using the following command:

composer update

We should now be able to run the bin/behat command to work with Behat.


Creating Features

We always begin by creating a new feature. A feature is something that we can use to describe a feature of our application and then implement it to get the test to pass.

A feature, at its simplest, consists of:

  • Human-readable, plain text.
  • Uses a .feature extension.
  • Contains the feature's benefit, role, and the feature itself.
  • May hold a list of scenarios.

Now I can't show you how to test all possible features for an application, as that would take far too long. But what I can do is show you how to go about writing a basic feature and you can adapt this code to make it work for your specific application.

Testing the Phpadder Class

To avoid complicating the learning process, let's create a very simple Phpadder.php file which contains a couple methods that we can use to add two numbers together and display their sum.

class Phpadder {

	private $a;
	private $b;
	public $sum;

	public function __construct($a, $b) {
		$this->a = $a;
		$this->b = $b;
	}

	public function add() {
		$this->sum = $this->a + $this->b;
	}

	public function display() {
		return $this->sum;
	}
}

This creates a new class named Phpadder. We have a few properties to hold the first ($a) and second ($b) numbers to be added, as well as a $sum property to hold the values's sum.

Next, we have our constructor which initializes our properties. Then we have an add method to add the two numbers together and finally a display method to display the sum of the two numbers.

Adder Feature

Let's now test this Phpadder class. Create a new .feature file along with the following code:

# features/phpadder.feature
Feature: adder
	In order to display the sum of two numbers
	As anybody
	I need to provide two numbers

We start out by giving our feature a name of adder. Then we specify, on three lines, the feature's benefit, role, and finally the feature itself. It should be fairly self explanatory.

Now that we have our feature, let's start writing our scenarios.


Creating Scenarios

Anytime we create a feature we can define scenarios that describe how that feature behaves given certain conditions. Scenario's follow the same basic layout consisting of the scenario's description, a context, an event, and an outcome.

Let's create a scenario to test out our Phpadder application:

Scenario: Display the sum of two provided numbers
	Given I have the number 50 and the number 25
	When I add them together
	Then I should get 75

We begin with our scenario description, we then list out that we start with the two numbers of 50 and 25 and when they are added together it should display the sum of 75.

You can also have multiple contexts, events, and outcomes as well using the following keywords: And and But. Here's a modified example of the previous scenario where we'll use And:

Scenario: Display the sum of two provided numbers
	Given I have the number 50 and the number 25
	And I have a third number of 25
	When I add them together
	Then I should get 100

Creating Step Definitions

A step is nothing more than a PHP function which is made up of a keyword, a regular expression, and a callback function. Each statement within your scenario will be matched to a step. These steps define what should happen given one of your statements are called within a scenario. You store all of your steps within the features/bootstrap/FeatureContext.php file.

The "Given" Step

In our FeatureContext.php file (you may need to create this), we need to write a step for each of our statements, using its name as the function name. We'll start with the "Given I have the number" statement:

# features/bootstrap/FeaturesContext.php

require("Phpadder.php");

use Behat\Behat\Context\BehatContext, 
	Behat\Behat\Exception\PendingException;

use Behat\Gherkin\Node\PyStringNode,
	Behat\Gherkin\Node\TableNode;
	
class FeatureContext extends BehatContext {

	private $Adder;
	
	/**
	 * @Given /^I have the number (\d+) and the number (\d+)$/
	 */
	public function iHaveTheNumberAndTheNumber($a, $b) {
		$this->Adder = new Phpadder($a, $b);
	}

First, we create a new PHP file, require in our Phpadder.php file (the file that we're testing), and then we use a few Behat classes with use statements, right after.

Next, we create our FeatureContext class and have it extend the BehatContext class.

Our class has only one property, $Adder, which will hold a Phpadder object.

Finally, we create a method for our first step using the same name as the statement. Our step has a regular expression, found within the method's comment. This regular expression is used to match the step to a scenario statement. Within this method we simply assign a new Phpadder object to our $this->Adder property so that the rest of our methods have access to the same Phpadder object.

Now, you've probably noticed the @Given keyword within your function's comment, this is actually an annotation so that the different types of steps can be identified. You can use @Given, @When, and @Then.

Now we just need to write the last two steps.

The "When" Step

/**
 * @When /^I add them together$/
 */
public function iAddThemTogether() {
	$this->Adder->add();
}

This step simply uses our $this->Adder object's add method to add the two numbers together.

The "Then" Step

/** 
 * @Then /^I should get (\d+)$/ 
 */
public function iShouldGet($sum) {
	if ($this->Adder->sum != $sum) {
		throw new Exception("Actual sum: ".$this->Adder->sum);
	}
	$this->Adder->display();
}

This step starts off by checking if the actual sum (retrieved using our $this->Adder object and its sum property) is not equal to the expected sum. If this evaluates to true that means we need to have Behat show a failure. To do so, we'll just throw a new exception displaying the actual sum so we can compare. Otherwise, we call our display method.

Time to run the tests.


Running the Tests

Now that we have our features, scenarios, and steps laid out, let's run our tests using the following command:

bin/behat

You should see the following success messages inside of your terminal:

testing-success

You can ensure that your tests are running correctly, by simply breaking something in your Phpadder.php file so that it doesn't run quite the same way your test expects it to. For example, if we change the add method to instead use subtraction, like so:

public function add() {
	$this->sum = $this->a - $this->b;
}

And then we rerun our tests: bin/behat. You can see in our terminal, we now have a failing test, because it's no longer adding our numbers but subtracting them:

testing-fail

Conclusion

In conclusion, you can follow a small four step process for testing your PHP apps using Behat:

  1. Define a Feature
  2. Define a Scenario
  3. Define Step Definitions
  4. Run the tests using bin/behat

So, with just that small amount of code, we should now have a basic understanding of how to work with Behat to test our PHP applications. For more information about working with Behat please checkout their documentation.

Related Posts
  • Code
    Android SDK
    Create a Music Player on Android: User Controls0d63m preview image@2x
    We are building a simple music player app for Android in this series. So far, we have presented a list of the songs on the device and allowed the user to make selections from it, starting playback using the MediaPlayer class in a Service class. In this final part of the series, we will let the user control playback, including skipping to the next and previous tracks, fast-forwarding, rewinding, playing, pausing, and seeking to particular points in the track. We will also display a notification during playback so that the user can jump back to the music player after using other apps.Read More…
  • Code
    Web Development
    Laravel Unwrapped: Session, Auth and CacheLaravel wide retina preview
    Join me as we learn how to use Laravel's component-based system, Illuminate. Additionally, we'll see how to utilize service providers, Laravel's manager system, the Session, Auth, and Cache components, and the Store, Guard, and Repository libraries.Read More…
  • Code
    PHP
    SOLID: Part 4 - The Dependency Inversion Principle4 dip retina
    The Single Responsibility (SRP), Open/Closed (OCP), Liskov Substitution, Interface Segregation, and Dependency Inversion. Five agile principles that should guide you every time you write code.Read More…
  • Code
    PHP
    Setting Up a Local Mirror for Composer Packages With SatisComposer retina preview
    Installing all your PHP libraries with Composer is a great way to save time. But larger projects automatically tested and run at each commit to your software version control (SVC) system will take a long time to install all the required packages from the Internet. You want to run your tests as soon as possible through your continuous integration (CI) system so that you have fast feedback and quick reactions on failure. In this tutorial we will set up a local mirror to proxy all your packages required in your project's composer.json file. This will make our CI work much faster, install the packages over the local network or even hosted on the same machine, and make sure we have the specific versions of the packages always available.Read More…
  • Code
    PHP
    Validation and Exception Handling: From the UI to the BackendProcedural to oop php retina preview
    Sooner or later in your programming career you will be faced with the dilemma of validation and exception handling. This was the case with me and my team also. A couple or so years ago we reached a point when we had to take architectural actions to accommodate all the exceptional cases our quite large software project needed to handle. Below is a list of practices we came to value and apply when it comes to validation and exception handling.Read More…
  • Code
    PHP
    Acceptance Testing With CodeceptionIntro to codeception retina preview
    Typically new features for web applications are tested by visiting the appropriate page in a browser, maybe filling out some form data, submitting the form, and then developers or testers hope to see their desired result. This is the natural way most web developers test their apps. We can continue with this natural testing process and improve upon it to ensure our apps are as stable as possible by using Codeception. Read More…