This tutorial has a new version, check it out!


Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.


Hey! Welcome to the tutorial that we’re calling “All about the World of Behat”. Our goal is simple: to understand the Behavior-Driven Development philosophy and master two tools - Behat & Mink - that will make you a functional-testing legend.


Behat and Mink have been developed by the open source community and are led by our friend and yours: Konstantin Kudryashov - aka @everzet: He was a huge help in the creation of this course!

Why test your application? Well imagine you are running Jurassic Park, you need to know that adding the new Pterodactyl exhibit won’t turn off the electric fence around the velociraptor pen. Don’t have any tests? Good luck - they know how to open doors.

Getting good at practicing behavior-driven development - or BDD - means more than learning a new tool, it will change your entire development process for the better. Imagine a world where communication on your team is perfect, you always deliver exactly what your client wanted, electricity on the velociraptor fence never goes down and chocolate ice cream is free. Ok, we can’t promise all of that, but we’ll see how BDD makes developing fun all over again.

In this first part, I’m going to show you how to install everything you need and write your first feature and scenarios. After that, we’ll back up to learn more about each important part: scenarios & features, step definitions, advanced Mink, and other really important topics.


Before we begin, let’s install a few libraries. Start by creating a new directory and adding a composer.json file.


If you’re testing an existing application, do all of this inside your project directory.

Composer is a tool that helps download external libraries into your project. If you’re not familiar with it, it’s totally ok! We have a free course that explains it.


Watch “The Wonderful World of Composer Tutorial” at

We’ll be downloading Behat, Mink, and a few other related libraries into our project. To make this easy, we’ve prepared a gist with exactly what you need to add to your composer.json.

    "require": {
        "behat/mink": "1.4@stable",
        "behat/mink-goutte-driver": "*",
        "behat/mink-selenium2-driver": "*",
        "behat/behat": "2.4@stable",
        "behat/mink-extension": "*"
    "minimum-stability": "dev",
    "config": {
        "bin-dir": "bin/"


If you’re using Behat in a Symfony2 project, you’ll also want to include the Symfony2 Extension.

Next, download Composer by going to and clicking download. Copy one of the two code blocks, depending if you have curl installed, and paste into the terminal. This downloads a standalone composer.phar executable.


Remember, we talk a lot more about composer in “The Wonderful World of Composer Tutorial” at

Next, tell Composer to download the libraries we need by running php composer.phar install

$ php composer.phar install --prefer-dist

We’ll fast-forward through this thrilling process as it downloads each library and places it into a new vendor/ directory. When it’s finished, you’ll also notice a new bin/ directory with a behat file in it. This is the Behat executable, and you’ll use it to run your tests and get debug information.

Next, create a behat.yml file at the root of the project. When Behat runs, it looks for a behat.yml file, which it uses for its configuration.


For more information about the behat.yml configuration file, see Configuration - behat.yml.

We’ll use it to activate MinkExtension, which is like a plugin for Behat. Also, we’re going to test Wikipedia, so use it as the base_url. If you’re testing your application, use its local base URL instead. Hopefully you’ll join us for the rest of this course, where we’ll go into greater detail.

      goutte:    ~
      selenium2: ~


If you’re using Behat with Symfony2, you should also activate the Symfony2 Extension that you added to composer.json:

    # ... the MinkExtension code
    Behat\Symfony2Extension\Extension: ~

To get the project ready to use Behat, run php bin/behat --init. This creates a features/ directory and a bootstrap/FeatureContext.php file inside of it.


If you’re using Behat in Symfony2, run the command for a specific bundle. A Features directory will be created in that bundle, with a similar structure. If the directory is created at the root of your project, delete it and double-check that you’ve activated the Symfony2Extension in the behat.yml file:

$ php bin/behat @EventBundle --init

Open this file and make it extend MinkContext instead of BehatContext:

// ...
use Behat\MinkExtension\Context\MinkContext;

class FeatureContext extends MinkContext
    .. ///

Later on, we’ll learn more about Behat and Mink individually, and the importance of the MinkContext class will make more sense.

Woo! With all that installing and configuring behind us, let’s get to locking down the raptor cage!

Writing Features and running tests

The Behat and Mink libraries are most commonly used to test web applications. You describe a feature in a human-readable syntax called Gherkin, then execute these as tests. The best way to see this in action is to take your DeLorean back to the past a few years and imagine that Jimmy Wales has asked you to build Yes, we know this site actually exists, but we’re going to describe its behavior and run some functional tests against it.

First, forget about tests. Our goal is to describe the feature. We’re going to describe the Wikipedia search, so create a search.feature file in the features directory. The language in this file is called Gherkin and you start by describing the feature using a specific, four-line syntax. This defines the business value of the feature, who will benefit from it, and a short description. So, when John Hammond comes to you with a big idea, your first goal should be to try to describe it using these four lines. Writing good feature descriptions is really important, and we’ll spend more time on this later.

Feature: Search
  In order to find a word definition
  As a website user
  I need to be able to search for a word

Each feature has many scenarios, which describe the specific behavior of the feature. Each scenario has 3 sections. Given which details the starting state of the system, When which includes the action the user takes, and Then which describes what the user sees after taking action. In this scenario, we’re searching for an exact article that matches.

  # ...

  Scenario: Search for a word that exists
    Given I am on "/wiki/Main_Page"
    When I fill in "search" with "Velociraptor"
    And I press "searchButton"
    Then I should see "an enlarged sickle-shaped claw"

Great! In a normal application, we’d now start developing the feature until it it fits our description of its behavior. But since Wikipedia exists already, we can see the behavior in action!

Writing Features and Scenarios is great, because it helps clarify how something should work in human-readable language. But the real magic is that we can run the scenario as a functional test!

To do this, run php bin/behat. Behind the scenes, this reads the scenario and actually uses a real browser to go to Wikipedia, fill in the field, and click the button!

To see how this is possible, execute Behat, but pass a -dl option:

$ php bin/behat -dl

Behat’s job is to read each line in the scenario and execute some function inside our FeatureContext class. Because we’re using Mink, we inherit a lot of common sentences. You can use these to write tests without writing any PHP code. You can also invent your own sentence and then create a new method in the FeatureContext class. We’ll talk a lot more about this later.

Executing Tests that use JavaScript

Our first scenario ran in the background using a headless browser called Goutte. Goutte runs very fast, you know like a velociraptor, but it doesn’t support Javascript. This was ok because our Scenario doesn’t rely on any JavaScript functionality. But what if it did? Can we test things that use JavaScript?

Of course! And with Behat & Mink, it’s incredibly easy. First, download Selenium Server, which is just a jar file that can live anywhere on your computer. Start Selenium at the command line by running java -jar followed by the filename.

$ java -jar selenium-server-standalone-2.28.0.jar

Now for the magic. To make this one scenario execute using Selenium instead of Goutte, add an @javascript tag above the scenario. Now just re-run your Behat tests using the same command as before:

$ php bin/behat

Magically, a browser opens up, surfs to Wikipedia, fills in the field and presses the button. This is the most powerful feature of Mink: you can run some tests using Goutte and other tests - that require JavaScript - in Selenium simply by adding the @javascript tag.

Digging into Gherkin, Behat and Mink

We now have a project using Behat & Mink, and our first feature file and scenario. Using a bunch of built-in english sentences, we’re able to write tests without any work at all.

But to really get good, we need to dive deeper to find out how to write really solid Feature files, how to create your own custom sentences, how to master Mink to do really complex Browser tasks, and much more. So, keep going!

Leave a comment!

  • 2018-03-16 Nancy Rai

    Very nice, simple and comprehensive article on REST API. thumbs up
    I am sharing another good article related REST API :
    Hope it help others..

  • 2018-01-02 Victor Bocharsky

    Hey Łukasz,

    Glad you got it working!


  • 2017-12-29 Łukasz

    Thanks, i figure out this. I run php -S localhost:8000 from project folder not form /web folder and that was the reason.

  • 2017-12-29 Victor Bocharsky

    Hey Łukasz,

    We don't run "php testing.php" in this screencasts, it's a bit early to start playing with testing.php on this page :)

    Did you download the code, go to the start/ directory and read the file inside? You need to do some preconditions at first which are explained in the README file.

    Also, try to successfully go through all the screencasts to when we start executing "php testing.php" for the first time. And tell me what screencast exactly you are stuck on.


  • 2017-12-27 Łukasz

    Hej, after run "php testing.php" i get </head><body><h1>Not Found</h1>

    The requested resource /api/programmers was not found on this server.


  • 2017-05-08 Techin To

    Okay great! Thank you!!!

  • 2017-05-08 Diego Aguiar

    Hey Techin To

    Symfony 2.3 has a few more deprecations than 2.8, but I don't think it would cause you a lot of problems.

    This tutorial might help you for detecting deprecations:
    if not, it is fun to watch anyways ;)

    Have a nice day!

  • 2017-05-08 Techin To

    This is great to know! How about for version 2.3? Should I also follow Symfony 3 tutorial as well?

  • 2017-05-04 weaverryan

    Hey fatih!

    I'd definitely recommend going through the Symfony 3 tutorial, not the Symfony 2 tutorial - it's much more relevant. Really, the biggest (maybe only) difference will be some directory structure changes that you'll notice in the Symfony 3 tutorials versus your project. I talk about those differences here - - they're pretty minor actually!

    So, get to it! And good luck :)


  • 2017-05-03 Fatih

    Guys, I am working in a company and they use symfony 2.8 for developing an e - commerce product. They want me to learn symfony2, should i take this tutorial or symfony3 tutorial?

  • 2017-04-19 Ben

    Thank you!

  • 2017-04-17 weaverryan

    Yo Ben!

    Try also doing a apt-get install php7.0-sqlite3 (replacing 7.0 with your actual PHP version, like 5 or 7.1). You DID install sqlite3 (good catch on that - that was the correct thing to do) - but you also need the sqlite extension for PHP. It comes pre-installed with most PHP's... but curiously, not all PHP installations :).


  • 2017-04-16 Ben

    Hi when i run php data/setupDb.php it says
    'Panic! could not find driver'. I have sqlite3 installed i just did a sudo apt install sqlite3.

    What else could be the problem?

  • 2016-11-22 Victor Bocharsky

    Hi MassiB,

    We're talking about REST API in general here, but if you're interested in OAuth only - we have a tutorial about OAuth2:


  • 2016-11-22 MassiB

    I'm not sure - are we referring to Oauth or Oauth2 here?

  • 2016-09-18 shilpagov82

    This could be useful in helping you monitor REST APIs for performance and accuracy. Uptime Cloud Monitor supports monitoring REST APIs on a completely SAAS based model.
    The setup is quick and easy. You can configure the REST API URL, the REST method (GET/ POST/ PUT/ DELETE), request parameters (if any), credentials required (if any), the monitoring frequency, the geographic location of the monitoring stations (from a choice of 15 stations across the globe). You can match the REST API response body against a specific string to ensure that the response is as expected.

    You can also configure alerts (notified via SMS, Email, PagerDuty etc) to be triggered based on API downtime, performance degradation or API response verification failure.

    More details on REST API Monitoring:

    You can also sign up for a 14 day free trial of Uptime Cloud Monitor

    Disclaimer: I work at Uptime Cloud Monitor

  • 2016-05-11 weaverryan

    Hi Sudhir!

    1. Your code for this part looks perfect, so I'm a bit confused to why you are being redirected incorrectly. When you view the HTML source of your page, do you see this?


    Or is the app_dev.php missing from this string? Also, try using window.location = '' instead of replace - just in case that's causing problems.

    2. I'm not sure about this. What do you mean that it doesn't work when the method is POST? Do you mean that the AJAX request causes a 404? Or that it works but you cannot access your POST data? If you're not using the build-in web server, what web server are you using? Also, even if you're not using the built-in web server, you should point your web server at the "web" directory as the document root so that you have nice URLs like /app_dev.php/login (without the /web in front) :).


  • 2016-05-11 Sudhir Gupta

    hi weaverryan

    hope u r doing good.
    in my current project i am facing a 2 issue.
    here is my problem statement.

    1. i am sending a ajax request to validate the login. when valid credentials matched i am trying to redirecting on dashboard.
    my current url is www.projectUrl//web/app_dev.php/login/
    after that i want to redirect at www.projectUrl//web/app_dev.php/flight/
    in js file here is my code

    window.location.replace('{{ path ("/flight")}}');

    using this code the redirection is going on /login/flight. (i want app_dev.php/flight/). may u help me where i am doing worng.

    2nd issue.
    when i am using /web/app_dev.php/login/ (without symfony server:run) my post method didn't work. ajax is working fine but i am not getting Post variable. surprising thing is if i am using GET method then its work never when i use POST.

    Here is my ajax code.

    url : httpPath, // path via parameter
    data: serializeData,
    method: 'POST',
    cache: false,
    contentType: 'application/json',
    timeout: 5000,

    may u help me where i am doing wrong..

    Thanks in advance.

  • 2016-05-04 weaverryan

    Ah, you're right - there's a problem in the dependency-injection tutorial - I just fixed this: Thanks for pointing that out! I wanted to give you a proper GitHub shout, but I was only 90% sure that jhmnieuwenhuis is you :).

    I plan to script out those installation instructions so that we can't possibly mess them up - you know, keeping docs in sync with code... not always easy.


  • 2016-05-04 Hans Nieuwenhuis

    Ok, great.
    But there is still no vendor directory in the start code.
    And in the it says :

    "You can also run Composer, though the `vendor/` directory should already have everything it needs:"

    And if there is no vendor directory and composer is not run, the start code will not run.



  • 2016-05-03 weaverryan

    Thanks Hans! We just fixed that - we left a library in there that's not used anymore :)

  • 2016-05-01 Hans Nieuwenhuis

    Update course code ?

    In the course code composer.json there are still the lines for knpuniversity/gladiator.
    And there is no vendor directory.

    When I run composer install I get an error on gladiator, saying it can not be downloaded.
    And I think it is nog longer needed or ??

    I removed the gladiator lines from composer.json and removed composer.lock and then I ran
    composer install again, and now the application works...

    Later on I also ran composer require pimple/pimple, and that also works fine/

  • 2015-11-05 Ammar

    Hey thanks. It works perfectly now!

  • 2015-11-04 weaverryan

    Hey Ammar!

    It's an easy fix: just create a `logs` directory at the root of the project and make it writeable - the code is trying to write to a mail.log file in this directory. I just added a note about this to the project:


  • 2015-11-04 Ammar

    i get this error on running app.php

    PHP Warning: fopen(/var/www/public/dependency_injection/src/DiDemo/Mailer/../../../logs/mail.log): failed to open stream: No such file or directory in /var/www/public/dependency_injection/src/DiDemo/Mailer/SmtpMailer.php on line 56

    PHP Warning: fwrite() expects parameter 1 to be resource, boolean given in /var/www/public/dependency_injection/src/DiDemo/Mailer/SmtpMailer.php on line 57

    PHP Warning: fopen(/var/www/public/dependency_injection/src/DiDemo/Mailer/../../../logs/mail.log): failed to open stream: No such file or directory in /var/www/public/dependency_injection/src/DiDemo/Mailer/SmtpMailer.php on line 56

    PHP Warning: fwrite() expects parameter 1 to be resource, boolean given in /var/www/public/dependency_injection/src/DiDemo/Mailer/SmtpMailer.php on line 57

    i am assuming the log files are not being generated due to sqlite db connectivity issues. I am using scotch box vm and it comes it sqlite. How do i setup a username and pass in setupdb.php?

  • 2015-10-26 David Thorne

    Thanks Ryan, helps a lot. I'll hold off till 2.8/3.0 are out and videos are completed. Looking forward to them, keep up the good work!

  • 2015-10-26 weaverryan

    Hey David!

    Actually, since Symfony 2.8 and 3 come out in about a month, we'll start to record complete updates to the latest versions really soon. Until then (as you eluded to), I would wait to learn Symfony. If we show you an out-dated way of doing something, you'll get a deprecation warning in the web debug toolbar - so you'll know it's outdated. More importantly, the new way is usually pretty close (e.g. a method name change) from the way we show things.

    I hope that helps - updates coming soon!

  • 2015-10-26 David Thorne

    Whilst Symfony 2.4 is still an officially supported LTS release, it is no longer the standard LTS if you follow the Symfony best practices. Whilst putting together a whole new series on 2.7 is a lot of work, any chance on either a mini series on the core differences or indeed a single video if that seems more applicable?

  • 2015-07-12 weaverryan

    Hey Léo!

    You're really close :). You need to move into the "start" directory and run a "composer install" (or a php composer.phar install depending on how you have Composer installed). We do talk about this - but it's a few more chapters from now :)

    Let me know if that helps!

  • 2015-07-12 Léo Li

    Excuse me, when I ran this "php app.php", I got a error:

    PHP Warning: require(/Users/AJ/Sites/knpuniversity-dependency-injection/start/vendor/autoload.php): failed to open stream: No such file or directory in /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php on line 3

    PHP Stack trace:

    PHP 1. {main}() /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php:0

    Warning: require(/Users/AJ/Sites/knpuniversity-dependency-injection/start/vendor/autoload.php): failed to open stream: No such file or directory in /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php on line 3

    Call Stack:

    0.0008 228408 1. {main}() /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php:0

    PHP Fatal error: require(): Failed opening required '/Users/AJ/Sites/knpuniversity-dependency-injection/start/vendor/autoload.php' (include_path='.:/usr/local/Cellar/php56/5.6.3/lib/php') in /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php on line 3

    PHP Stack trace:

    PHP 1. {main}() /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php:0

    Fatal error: require(): Failed opening required '/Users/AJ/Sites/knpuniversity-dependency-injection/start/vendor/autoload.php' (include_path='.:/usr/local/Cellar/php56/5.6.3/lib/php') in /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php on line 3

    Call Stack:

    0.0008 228408 1. {main}() /Users/AJ/Sites/knpuniversity-dependency-injection/start/app.php:0

    And I can't find __DIR__.'/vendor/autoload.php' this file in the package, neither the "logs\mail.log".
    Am I missing some step?