Buy

From Install to JS Testing

Welcome to the magical world of Behat, my favorite library. No joke this thing is the best. Behat is about two things:

BDD, Functional Testing and... Planning a Feature???

First, functionally testing your application. Which means writing code that will open a browser, fill out a form, hit submit and verify text on the other side.

Why test your application? Well, imagine you are in charge of safety at Jurassic Park, your job is to make sure guests aren't eaten by dinosaurs. You need to be certain that the new pterodactyl exhibit that's being put in won't turn off the electric fence around the velociraptor pen. No tests? Good luck, they know how to open doors.

And second, designing your application. As developers we'll often just start coding without thinking about what we're building or how the feature will behave.

Using behavior driven development, which Behat helps you do, you'll actually plan things out beforehand.

Imagine a world where communication on your team is perfect, you always deliver exactly what your client wants, electricity on the raptor fence never goes down and chocolate ice cream is always free. Yep, that's where we're going.

Behat Docs

Over in the browser, let's surf to the Behat documentation. In this tutorial we're covering version 3, and for whatever reason when I recorded this the website still defaults to version 2.5. So double check that you are actually looking at version 3's documentation.

I've got our project, the raptor store, loaded here. This is where dinosaurs go for the newest iphone and other cool electronics. There's a homepage, an admin section and that's basically it. This store is built using a very small Symfony2 application -- but hey, don't panic if you're not using Symfony: everything here will translate to whatever you're using.

Cool, we've got a search box, let's look up some sweet Samsung products. And here are the two results we have. I want to start this whole Behat thing by testing this. Hold onto your butts, let's going to get this thing running!

Install and Configuration

Over in the terminal run composer require and instead of using behat/behat we'll grab: behat/mink-extension and behat/mink-goutte-driver:

composer require behat/mink-extension behat/mink-goutte-driver

These are plugins for Behat and another library called Mink and they require Behat and Mink. We see the Mink library downloaded here, and the Behat library downloaded down there. So life is good!

Once you've downloaded Behat you'll have access to an executable called ./vendor/bin/behat or just bin/behat for Symfony2 users. Running it now gives us a nice strong error:

vendor/bin/behat

That's ok because we need to run it with --init at the end just one time in our application:

vendor/bin/behat --init

This did an underwhelming amount of things for us. It created two directories and one file.

In PhpStorm we see a features directory, a bootstrap directory and a little FeatureContext.php file and that's all of it:

24 lines features/bootstrap/FeatureContext.php
... lines 1 - 2
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
... lines 5 - 6
... lines 8 - 10
class FeatureContext implements Context, SnippetAcceptingContext
{
... lines 13 - 19
public function __construct()
{
}
}

While we're here, I'll add a use statement for MinkContext and make it extend that. I'll explain that in a minute:

25 lines features/bootstrap/FeatureContext.php
... lines 1 - 6
use Behat\MinkExtension\Context\MinkContext;
... lines 9 - 11
class FeatureContext extends MinkContext implements Context, SnippetAcceptingContext
... lines 13 - 25

One last bit of setup: at the root of your project create a behat.yml file. I'll paste in some content to get us started:

6 lines behat.yml
default:
extensions:
Behat\MinkExtension:
base_url: http://localhost:8000
goutte: ~

When we run Behat it will looks for a behat.yml file and this tells it:

Yo! Our application lives at localhost:8000, so look for it there.

Your First Feature and Scenario

Behat is installed, let's get to writing features! In the features directory create a new file called search.feature and we'll just start describing the search feature on the raptor store using a language called Gherkin which you're about to see here.

11 lines features/search.feature
Feature: Search
In order to find products dinosaurs love
As a website user
I need to be able to search for products
... lines 5 - 11

Here I'm just using human readable language to describe the search feature in general. Within each feature we'll have many different scenarios or user flows. So let's start with Scenario: Searching for a product that exists. Now using very natural language I'll describe the flow.

11 lines features/search.feature
... lines 1 - 5
Scenario: Search for a word that exists
Given I am on "/"
When I fill in "searchTerm" with "Samsung"
And I press "search_submit"
Then I should see "Samsung Galaxy S II"

Don't stress out about the formatting of this, we'll cover that in detail.

The only two things that should look weird to you are searchTerm and search_submit because they are weird. searchTerm is the name attribute of this box here, and search_submit is the id of this button. We'll talk more about this later: I'm actually breaking some rules. But I want to get this working as quickly as possible.

Running Behat

Ready for me to blow your mind? Just by writing this one scenario we now have a test for our app. In the terminal run ./vendor/bin/behat and boom! It just read that scenario and actually went to our homepage, filled in the search box, pressed the button and verified that "Samsung Galaxy" was rendering on the next page. Why don't we see this happen? By default, it runs things using invisible curl request instead of opening up a real browser.

Testing JavaScript

The downside to this is that if you have JavaScript on your page that this scenario depends on, it isn't going to work since this isn't actually opening up a real browser. So, how can we run this in a real browser? There are actually a bunch of different ways. The easiest is by using Selenium.

Grab another library with composer require behat/mink-selenium2-driver. You'll also need to download the selenium server which is really easy, it's just a jar file. Click this link here under downloads to get the Selenium Standalone Server. I already have this, so I'm not actually going to download it.

To run things in Selenium, open a new tab in your terminal, and run the jar file that you just downloaded. For me that's

java -jar ~/Downloads/selenium-server-standalone-2.45.0.jar

This will load and run as a daemon, so it should just hang there.

Our library is done downloading and we just need to activate it in our behat.yml with the line:

7 lines behat.yml
default:
extensions:
Behat\MinkExtension:
... lines 4 - 5
selenium2: ~

This gives me the option to use goutte to run the test using curl requests or Selenium to have things run in a browser. By default, this will just select goutte. So how do we make it use Selenium? I'm so glad you asked!

Above the scenario that you want to run in Selenium add @javascript:

12 lines features/search.feature
... lines 1 - 5
@javascript
Scenario: Search for a word that exists
... lines 8 - 12

And that's it. Go back to the terminal and let's rerun this test. It actually opens the browser, it's quick but you can see it clicking around to complete the scenario. Cool!

We write human readable instructions and they turn into functional tests, and this just barely scratches the surface of how this will change your development. Let's keep going and figure out what's really going on here.

Leave a comment!

  • 2016-09-25 weaverryan

    Ah, great news!

  • 2016-09-23 Thierno Diop

    I notify the owner of the server about the problem and he fixed it buy setting varnish Thx a lot

  • 2016-09-23 weaverryan

    Yea, I agree that it sounds like a session-saving issue. But since you say that you *can* see session files created, and that they are created on each request, then it makes me wonder if Varnish is stripping the cookies so that each request (to Symfony) looks like a fresh request (i.e. one that has no cookie). I would remove Varnish, at least to test, and see if that fixes the problem.

    Cheers!

  • 2016-09-22 Thierno Diop

    No i did that dump to verify if the session was working i asked to the owner of the server he tell me that he installed varnish and since i juste replaced a project who was on the server with mine i mean its the same domain i think that is the problem

  • 2016-09-22 Victor Bocharsky

    The PHPSESSID does not store in cookies for this domain. You can see it in Google Chrome Developer Tool. I think it's because you have a dump statement in DefaultController.php on line 17. Please, remove it and check again.

  • 2016-09-22 Thierno Diop

    My hostname is senegeek.com so i think thats not the problem

  • 2016-09-22 Victor Bocharsky

    One possible cause for this is having a host name without a domain part (.com, .org, etc.), e.g. http://example/ instead of http://example.com/

  • 2016-09-22 Thierno Diop

    Thx for your response
    Session are saved in the folder var/sessions but the problem is that for every request it create one file in the session folder

  • 2016-09-22 Victor Bocharsky

    Hey Thierno,

    You should configure session properly - most likely session can't be stored on your server. Where do you store session? If it stores in files - look at save_path option and ensure you setup permissions for it correctly on the server. Let me know if it helps.

    Cheers!

  • 2016-09-21 Thierno Diop

    Hi Ryan i have a probleme with the guard authentication I use symfony 3.1 in my project the guard authentication work fine in my local machine but when i deploy to the server if the authentication succed i am redirecting to the home page but i loose the authentication and become anonymous again.
    I set a session variable to show it in another page but it turn that the variable was deleted .
    So i think that the session is deleted every request but i dont know why.
    Really need help Thx

  • 2016-07-25 Victor Bocharsky

    Hey ciudadano82 ,

    You don't have to install GuardBundle for Symfony 3.1 because Guard Component provides with Symfony out of the box since Symfony 2.8, so just start using it without installation! :)

    Check this blog post page for more information: http://symfony.com/blog/new-in... .

    Cheers!

  • 2016-07-21 ciudadano82

    Hi! I'm having trouble trying to download the guardBundle with composer, i've installed symfony 3.1.2 (currently the last version available), but i get the following error:
    Your requirements could not be resolved to an installable set of packages.

    Problem 1
    - Conclusion: remove symfony/symfony v3.1.2
    - Conclusion: don't install symfony/symfony v3.1.2
    ....
    - don't install symfony/security-bundle v2.8.8|don't install symfony/symfony v3.1.2
    - Installation request for symfony/symfony == 3.1.2.0 -> satisfiable by symfony/symfony[v3.1.2].
    - Installation request for knpuniversity/guard-bundle ~0.1@dev -> satisfiable by knpuniversity/guard-bundle[0.2, 0.3, v0.1].

    Any help, please?

  • 2016-06-28 Viral Champanery

    yes, right .. that was the one of the concern about this. to update the version . i just tring to do the same as i got document in following link
    https://packagist.org/packages...

    In above link it shows in symfony 2.3 so that i was trying to do that .... thats fine..thanks to supporting .... its very to chat with you.. .. vchampanery@gmail.com keep in contact ...

  • 2016-06-28 Victor Bocharsky

    Hm, I think you need to update your Symfony application first, at least to the ^2.6 as we can see from dependencies, but it would be better upgrade to the 2.7 as this is a LTS (Long Term Support) version. Looks like this bundle can't be correctly installed on Symfony 2.3.

  • 2016-06-28 Viral Champanery

    sorry bro, i have tried in that also but it will give the same error ... may be the reason my symfony 2.3.* version .. but i am not sure about it

  • 2016-06-28 Victor Bocharsky

    That's because your symfony/security-bundle has unsatisfiable version. Could you try to update it to "symfony/security-bundle": "^2.6" in your composer.json file?

  • 2016-06-28 Viral Champanery

    hi,
    When i put this " "require" : { "knpuniversity/guard-bundle": "0.1" " in my composer.jsno file and try to composer update following error shows :

    Your requirements could not be resolved to an installable set of packages.

    Problem 1

    - Installation request for knpuniversity/guard-bundle 0.1 -> satisfiable by knpuniversity/guard-bundle[v0.1].

    - Conclusion: remove symfony/symfony v2.3.23

    - knpuniversity/guard-bundle v0.1 requires symfony/security-bundle ~2.6 -> satisfiable by symfony/security-bundle[v2.6.0, v2.6.1, v2.6.10, v2.6.11, v2.6.12, v2.6.13, v2.6.2, v2.6.3, v2.6.4, v2.6.5, v2.6.6, v2.6.7, v2.6.8, v2.6.9, v2.7.0, v2.7.1, v2.7.10, v2.7.11, v2.7.12, v2.7.13, v2.7.14, v2.7.2, v2.7.3, v2.7.4, v2.7.5, v2.7.6, v2.7.7, v2.7.8, v2.7.9, v2.8.0, v2.8.1, v2.8.2, v2.8.3, v2.8.4, v2.8.5, v2.8.6, v2.8.7].

    - don't install symfony/security-bundle v2.6.0|don't install symfony/symfony v2.3.23

    - don't install symfony/security-bundle v2.6.1|don't install symfony/symfony v2.3.23

  • 2016-06-28 Victor Bocharsky

    Hm, if you already installed guard library - that's not so bad. What error do you have during the GuardBundle installation?

  • 2016-06-28 Viral Champanery

    Hi victor,

    Thanks for giving me valuable time ,
    I have the my code in 2.3.23 symfony version and it allows me to add only guard but not guardBundle .so can you help me out with this. that i can make user login, changes password. functionality useing guardBundle in current version .. Is it possible to have with Fos.use bundle as well .. both in a one system ....

  • 2016-06-28 Victor Bocharsky

    Hey, Viral!

    There's the KnpUGuardBundle which you need to install first, because out-of-the-box Guard component available since Symfony ^2.8. only. But keep in mind that some dependencies should be updated to "^2.6". Check composer.json file of KnpUGuardBundle bundle to get more information about versions of dependencies.

    Cheers!

  • 2016-06-28 Viral Champanery

    Hi, i have my application in symfony 2.3 so can i integrate it with this . because when i put composer update i got error like this " Unrecognized options "knpu_guard" under "security.firewalls.main" " in my security.yml it is like " knpu_guard:
    authenticators:
    - app.form_login_authenticator "

  • 2016-02-15 Shaun

    Setting up the DB after downloading the course code was quite tricky, solved by trial and error, and really needs to be documented. From within ../start/
    1) php app/console doctrine:database:create
    2) php app/console doctrine:schema:update --force
    3) php app/console doctrine:fixtures:load

    Hopefully Ryan can review the steps above and check whether that's the best approach.

    (I just finished the Drupal 8 series by the way, and totally loved it. I just had to say that).

  • 2016-02-15 Daniel

    Thanks it worked, I all set with symphony 3 as well. Cheers!

  • 2016-02-11 weaverryan

    Hey Daniel!

    I have not totally set it up yet on Symfony 3, but I know at least that behat/mink is not compatible with Symfony 3 yet. Well, actually, it IS compatible - on its master branch, but there has not (yet) been a release with these compatibility changes. So, at the very least, you'll need to require behat/mink at the version dev-master. For Behat, you will need version 3.1 their of *their* library, which is not released fully yet. Try using ^3.1@dev in composer.json - or dev-master, that should do it.

    Some bundles/libraries have been slow to tag releases of their Symfony-3 compatible versions. It's made using some libs with Symfony 3 a pain. It should get better :).

    Cheers!

  • 2016-02-10 Daniel

    Hi Ryan! What about having this setup for BDD in symfony3? Have you tried it? I got a myriad of composer conflicts, too long to be put here

  • 2015-12-15 tomhv

    Awesome, thanks! That makes a lot of sense.

  • 2015-12-15 weaverryan

    This is a *great* question... so I talked to some of the guys at KnpLabs about it. I'll make a few points:

    1) The first important thing is communication. If *you* know that you will ultimately need features and scenarios, then when planning with your client, you should sit down and communicate (ask questions, etc) in a way that will ultimately allow you to easily write those features/scenarios. Using BDD clarifies your planning process, and you can use that to help your client plan.

    2) Regardless of whether you ultimately write the features/scenario or your client does (see my next point), you should validate the features/scenarios with your client. That will get them invested in the Gherkin process and avoid those ugly miscommunications about features :).

    3) I don't think it will always work, but you may be able to get your client invested enough in Gherkin that *they* start to write the scenarios. During our discussion about this, we basically agreed that you will always need to "translate" their scenarios a little bit (Gherkin is natural language, but it still has structure). Really, even my point (1) above was about translating your conversation with them into written scenarios. There will always be a translation step, but the smaller you can make that translation, the less translation "cost" you will have (time to translate, mistakes in not translating what they mean perfectly, etc).

    Thanks to these guys for our conversation about your cool question: https://github.com/Djeg and https://github.com/docteurklei...

    Cheers!

  • 2015-12-15 tomhv

    Where does Behat fit into the requirements-gathering process? Do you sit and write the features with the client?

  • 2015-11-13 AJ

    Thanks!

  • 2015-11-13 weaverryan

    Got it fixed now thanks to your comment!

  • 2015-11-13 AJ

    This video is different from the script. Was that intentional?