Talking English To Your Computer

In this video we are going to get started writing the code that turns the English language Behat feature into something that the computer - or more specifically, Behat itself, can run during our test suite execution.

Behat converts the text in your feature documents into code by way of regular expressions. Now, don't worry if your regex knowledge is only so-so. All we need to do is write the feature in English (or your native language), and then run Behat, and Behat will create snippets of code for you containing the regex, and the associated function stub.

I prefer to copy / paste these stubs into my Context files so I control exactly what's happening, but you can get Behat to append any new snippets / stubs directly in to your Context files for you if they don't yet exist. Find out more about that here, if you wish to use that feature.

Symfony 3 / Behat 3 Integration Update

Since I recorded the video on Installing Behat in Symfony 3, there has been further improvement on support between the two. A huge thank you to the community for this.

Whilst the changes have been made, currently they have not been officially merged into the respective packages / libraries / bundles, so I have taken what's there, and created an interim config / composer.json setup:

    "name": "a6_chris/",
    "license": "proprietary",
    "type": "project",
    "autoload": {
        "psr-4": {
            "": "src/"
        "classmap": [
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
    "require": {
        "php": ">=5.5.9",
        "symfony/symfony": "3.0.*",
        "doctrine/orm": "^2.5",
        "doctrine/doctrine-bundle": "^1.6",
        "doctrine/doctrine-cache-bundle": "^1.2",
        "symfony/swiftmailer-bundle": "^2.3",
        "symfony/monolog-bundle": "^2.8",
        "sensio/distribution-bundle": "^5.0",
        "sensio/framework-extra-bundle": "^3.0.2",
        "incenteev/composer-parameter-handler": "^2.0",

        "nelmio/cors-bundle": "^1.4",
        "nelmio/api-doc-bundle": "^2.11",
        "friendsofsymfony/rest-bundle": "^1.7",
        "csa/guzzle-bundle": "^2.0",
        "jms/serializer-bundle": "^1.1",
        "oneup/flysystem-bundle": "^1.2",
        "friendsofsymfony/user-bundle": "dev-master",
        "lexik/jwt-authentication-bundle": "dev-master"
    "require-dev": {
        "sensio/generator-bundle": "^3.0",
        "symfony/phpunit-bridge": "^2.7",

        "phpspec/phpspec": "^2.4",
        "behat/behat": "dev-master",

        "behat/mink": "^1.7",
        "behat/mink-extension": "^2.1",
        "behat/mink-browserkit-driver": "^1.3",
        "behat/symfony2-extension": "dev-symfony3"
    "minimum-stability": "dev",
    "repositories": [
            "type": "git",
            "url": ""
    "scripts": {
        "post-install-cmd": [
        "post-update-cmd": [
    "extra": {
        "symfony-app-dir": "app",
        "symfony-bin-dir": "bin",
        "symfony-var-dir": "var",
        "symfony-web-dir": "web",
        "symfony-tests-dir": "tests",
        "symfony-assets-install": "relative",
        "incenteev-parameters": {
            "file": "app/config/parameters.yml"

The important changes from last time are the inclusion of the repositories section, and the four additional behat packages inside require-dev.

As a side note, the repositories section is what allows me to reference behat/symfony2-extension by branch name, rather than by a tag. This is infrequently handy, and if you would like to know more, be sure to check out Lorna Jane's blog post - where I first learned about how to do this.

Our behat.yml File

For whatever reason, I didn't get a behat.yml file created for me when I ran vendor/bin/behat --init. Unless I am losing the last of my marbles, the --init argument has always generated me a behat.yml file for every previous project.

However, not to worry. If you also did not get a behat.yml file generated, then simply go ahead and create an empty file and name it as behat.yml. It should live in your project root - right along side composer.json and composer.lock.

Figuring out what to put in this file is a little tricker. To make life easier, here is mine, so far:

# behat.yml


      type: symfony_bundle
      bundle: AppBundle
        - FeatureContext:
            # doctrine: "@doctrine"

        env: "dev"
        debug: "true"

This is the simplest config needed to get Behat to run in our project.

We will be adding more to this file throughout the series, and even by the end of this video we will have added a little more.

This is largely why in the earlier video we couldn't run Behat. The Symfony 2 extension (a bit badly named now in Symfony 3 era) is what integrates your fully booted and ready to go Symfony kernel directly in to your Behat feature contexts. We can also inject all our Symfony services, just like in our Symfony services.yml file. Awesome.

We have configured one test suite - called default. As you can guess, this will be our default test suite. The type and bundle options are related to the Symfony2Extension.

The main area we will focus on is the contexts section. From here we can configure any and all of the context files we will use throughout our Behat test suite. More on this shortly, but if you are keen to know more, be sure to check out the official Behat docs.

Lastly, you can see that although commented out, the FeatureContext entry has a doctrine entry:

doctrine: "@doctrine"

A few important things to note here:

  1. This is how you would inject services in to your Behat features.
  2. The name of the property is really important - doctrine must match to $doctrine in your FeatureContext constructor (more on this soon)
  3. @doctrine is a standard way of referencing a Symfony service - bin/console debug:container for more
  4. Though not obvious, FeatureContext refers to a file by its namespace, any future contexts we create will have a longer path.

Don't worry if all of this is new to you, we will cover each piece as we go.

Keep Testing Separate

There's a situation that we don't want to get in to if we can avoid it. That is, we don't want to have our test suite run against the same environment we are developing under.

The reason for this is that with each test run, the entire database schema is going to be dropped and recreated. As such, if we were working on a bug in app_dev.php, and the test suite ran against app_dev.php, then should we have some perfectly reproduced bug environment going on in our development environment, then re-ran the tests, all our hard work would be dropped.

It might sound a little crazy, but I've done this to myself too many times in the past to not spend the two minutes it takes to mitigate this problem up front.

In the video we switch to app_acceptance.php for our testing. Why acceptance and not 'test'? Well, Symonfy already comes with a test environment and overriding that would be tricky. Besides, Behat is all about BEHavioural Acceptance Testing, so app_acceptance.php makes sense to me.

If you are unsure how to create a new environment, be sure to read the cookbook article on this very subject. Or just watch the video, it's very easy.

In the video I will show you how to configure the app/config/config_acceptance.yml to allow this environment to run properly during test.

Adding Mink Config

To finish up in this step, we are going to add in the Mink Extension config to allow our Behat features to properly interact with our RESTful API during test runs.

Mink is a browser automation software that will simulate a User interacting with our API.

Note, the change of env under the Symfony2Extension to match the environment we are now using in our MinkExtension config.

# behat.yml


      type: symfony_bundle
      bundle: AppBundle
        - FeatureContext:
            # doctrine: "@doctrine"

        env: "acceptance"
        debug: "true"

      base_url: ""
          symfony2: ~

With our behat.yml file looking like the above, we can go ahead and run Behat for the first time without expecting to see any configuration errors.


At this stage, not a great deal will happen, other than Behat showing all our steps / scenarios from the User Feature as pending / yellow.

More importantly though, Behat will generate all the first steps of each pending scenario for us, so we can copy and paste these into the relevant Context files.

This is hugely useful to us, and is exactly where we will begin in the next video.

Code For This Course

Get the code for this course.


# Title Duration
1 Project Introduction 17:13
2 Setting Up Our Development Environment 05:08
3 Installing Symfony 3, Behat, and more 13:53
4 User Feature - Part 1 17:48
5 User Feature - Part 2 07:51
6 Talking English To Your Computer 11:06
7 Teaching Your Database To Forget 07:43
8 Creating User Data From Behat Background - Part 1 14:44
9 Creating User Data From Behat Background - Part 2 11:33
10 Creating A Custom RestApiContext 17:45
11 Our First Passing Behat User Scenario 12:01
12 Our Next Passing Step 13:11
13 Securing Our User Endpoint - Part 1 17:18
14 Securing Our User Endpoint - Part 2 24:22
15 Securing Our User Endpoint - Part 3 24:47
16 Log In To A Symfony API With JWTs (LexikJWTAuthenticationBundle) 11:02
17 Implementing PATCH for Users 18:17
18 Improving our API User Experience 13:59
19 GET a Collection of Accounts 12:15
20 POSTing in New Accounts 14:35
21 PUT and PATCH for Accounts 12:15
22 How To DELETE Existing Accounts 05:11
23 File Feature Overview 11:40
24 File - Using Existing Resources as Boilerplate 15:17
25 File POST 14:54
26 Fixing A Bug In POST Guided By Behat 12:51
27 Wrapping Up With File DELETE 07:48