BDD stands for Behavior Driven Development and the idea is to test your application from end to end, like you would in a functional test but with tests that are written in human readable text. The problem of the usual functional testing is Javascript. You can easily test your API or webpage with PHPUnit but these tests will never execute any line of Javascript.
To solve this problem, you'll have to use quite a technology stack. At first it seems a bit overwhelming but after you set the whole thing up you don't have to worry about them any more. Don't worry we'll go through each of them, step by step. Here's the set of tools we are going to use:
- Gherkin Human readable testing language
- Behat Turns Gherkin language into PHP Tests
- Goutte Headless Browser that can access Webpages without Javascript
- Selenium Browser Emulator that uses Drivers to control real Browsers
- Mink Abstracts different browser emulators like Selenium or Goutte into one API
- Testingbot Online Selenium Server that supports Desktop, Mobile and Tablet Browsers
Gherkin
As a first step you will write your tests in a language called GHERKIN, what sounds complicated is actually pretty easy. You just write what you want to do step by step. Kinda what you do when you write a user story:
@javascript
Scenario: Searching for a page with autocompletion
Given I am on "/wiki/Main_Page"
When I fill in "search" with "Behavior Driv"
And I wait for the suggestion box to appear
Then I should see "Behavior-driven development"
Behat
Now how is that ever going to work? It's not as magic as it looks. Behat comes with a starting vocabulary. So it will know what to do for most of these commands except for the “I wait for the suggestion box to appear' part.
Once you execute the tests it will skip this and all succeeding parts but will prompt you with something very helpful. It builds the function glue layer. As it turns out all those Gherkin sentences are actually just PHP functions where the quoted text is a parameter.
You copy paste the function wrapper into your FeatureContext.php and fill in the missing code. Imagine it like Lego: you have a basic set of methods and you combine them to become more powerful methods.
The great thing about this is, you build your vocabulary. It almost forces you to write reusable code and so as the project goes on. Your vocabulary will grow. After a certain point your Project Owner will be able to write the Acceptance Criteria in Gherkin and you won't have to do a thing to have a test.
So the Code for our missing Lego brick looks like that:
/**
* @Then /^I wait for the suggestion box to appear$/
*/
public function iWaitForTheSuggestionBoxToAppear()
{
$this->getSession()->wait(5000,
"$('.suggestions-results').children().length > 0"
);
}
Ok now we know how we get from GHERKIN to actual php but where do these tests run?
Mink
Now that we have the function wrapper inside our FeatureContext.php file, we can use the Mink API to tell Goutte or Selenium what it has to do. The advantage of Goutte method is of course speed. But this method won't give you any Javascript capabilities. That's where Selenium comes in handy.
Selenium
Selenium uses drivers that directly connect with the browser. Other than testing libraries like buster.js (Unit Testing Framework) , it's directly communicating with the browser and not using Javascript.
You set up your Selenium server and install a bunch of browsers and drivers, right? Sure if all you need are desktop browsers then that's a pretty easy task. But as nowadays most websites need to work on Mobile Devices too, you'll have a hard time doing that yourself.
Testingbot
That's where Testingbot comes in. Easily said it's Selenium in a Cloud. You change the wd_host from your local Selenium Server to their remote one. Passing API and SECURE Key's in the process to identify yourself. Sounds almost to easy doesn't it?
Yeah there's one catch: Selenium doesn't know if the test succeeded or not. So Testingbot won't know that either. What you have to do is call their API with a HTTP request and tell them the outcome of every single test with the matching Selenium session_id.
A completed test will give you information about it's outcome and you can even watch a video of the device running it. Check out this completed test of our example.
Test it yourself
A working implementation of our little setup can be found on Github. You need to register yourself a Testingbot account and change the API and SECRET KEY in behat.yml. The Example will execute tests either on Firefox or on the iPhone depending which parameter you pass to the Behat command. Just take a look at the Readme.md, it should explain it all.
If you have questions, you're welcome to contact me on twitter: @nicam
Thanks for reading