Written by Maciej Kosiedowski
Published May 14, 2018

How to improve the quality of your PHP code? Part 3 – End-to-end / integration testing

In the final part of our series, it’s time to set up end-to-end / integration testing environment & ensure that we’re ready to check the quality of our work.

In previous parts of this series we’ve set up a build tool, few static code analyzers and started writing unit tests. If you haven’t read those, check them out!

To make our testing stack more complete, it’s good to have some tests which will check whether your code runs with real environments and whether it will perform well in more complex business scenarios.

Here we can utilize a tool built for Behavior Driven Development – official PHP’s Cucumber implementation – Behat. You can install it by running

php composer.phar require --dev behat/behat

And, of course, adding a target to build.xml (Phing setup was described in the first part of the article)

Then you should create a specification for a test in file features/price.feature:

This test scenario is pretty easy to read and should give you a good impression of how the feature is supposed to work. Unfortunately, computers usually don’t really understand human language, so now it’s time to write the code for each step.

You can generate the code template for it by running ./bin/behat --init. It should create a class looking like this:

Then you can run:
bin/behat --dry-run --append-snippets
Behat will automatically create functions for each step defined in the scenario.
Now you can start implementing the real checks by filling the functions’ bodies:

Finally, run all your tests using ./bin/phing. You should get the following result:

As you can see, Behat prepared a nice report stating what our application did and what was the result. Next time when your project manager will ask you which scenarios you covered with tests, you can just give him a Behat output!

Structure of the test

Each test consist of:

  • Some preparation of the scenario, expressed with “Given” part
  • Some action covered by “When” part
  • Some check noted as “Then” part

Each part can contain multiple steps concatenated with “And” keyword, eg.:


Behat allows you to define multiple contexts for your tests. This means that you can split your steps code into multiple classes, as well as test your scenarios from different perspectives.

You can eg. write code for web context which will run your test steps using your application HTTP controller. You can also create “domain” context which will run your business logic using just PHP API calls. This way you can, for instance, test your business logic integration separately from end-to-end application tests.

For more information on how to set up many contexts in Behat, please refer to the documentation at http://behat.org/en/latest/user_guide/context.html.

How can I use Behat?

As mentioned in the beginning, you can use Behat for integration tests. It is often the case that your code is dependent on some external 3rd party systems. When we were writing unit tests in part II, we always assumed that external dependencies are working as expected. With Behat you can write tests scenarios which will automatically run your code and check if it behaves correctly with real-world services.

What is most important, Behat is great for testing complex end-to-end scenarios of your system’s usage. It allows you to hide the complex code required to run test’s step behind a nice human readable name and write a scenario which everyone will understand.


You just learned how to set up six useful tools in your project:

  • PHing for running your builds
  • PHPCS for automatically checking your code style
  • PHPCPD for detecting duplicated code
  • Phan for advanced static code analysis
  • PHPSpec for unit testing
  • Behat for end-to-end and integration testing

Now, you can add ./bin/phing to your git commit hooks and set up your Continuous Integration to run tests with every commit. Suddenly nothing stops you now from being able to write quality PHP code! Well done!

Written by Maciej Kosiedowski
Published May 14, 2018