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/symfony.rest.example.dev",
"license": "proprietary",
"type": "project",
"autoload": {
"psr-4": {
"": "src/"
},
"classmap": [
"app/AppKernel.php",
"app/AppCache.php"
]
},
"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": "https://github.com/codereviewvideos/Symfony2Extension"
}
],
"scripts": {
"post-install-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
],
"post-update-cmd": [
"Incenteev\\ParameterHandler\\ScriptHandler::buildParameters",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::buildBootstrap",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::clearCache",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installAssets",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::installRequirementsFile",
"Sensio\\Bundle\\DistributionBundle\\Composer\\ScriptHandler::prepareDeploymentTarget"
]
},
"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
default:
suites:
default:
type: symfony_bundle
bundle: AppBundle
contexts:
- FeatureContext:
# doctrine: "@doctrine"
extensions:
Behat\Symfony2Extension:
kernel:
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:
- This is how you would inject services in to your Behat features.
- The name of the property is really important -
doctrine
must match to$doctrine
in yourFeatureContext
constructor (more on this soon) @doctrine
is a standard way of referencing a Symfony service -bin/console debug:container
for more- 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
default:
suites:
default:
type: symfony_bundle
bundle: AppBundle
contexts:
- FeatureContext:
# doctrine: "@doctrine"
extensions:
Behat\Symfony2Extension:
kernel:
env: "acceptance"
debug: "true"
Behat\MinkExtension:
base_url: "http://symfony-rest-example.dev/app_acceptance.php/"
sessions:
defaults:
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.
vendor/bin/behat
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.