How to Setup Behat Mink and Selenium for Symfony2

August 16, 2016 | No Comments | Programming | Behat PHP Symfony2 Testing

Symfony has a great toolset for functional testing. It’s useful in small projects but in big ones we need to use TDD or BDD techniques with big amount of tests. Suppose we need to integrate tools for testing with our project. Let’s review it on example with BDD toolset Behat Mink and Selenium for Symfony2.

Install packages

Composer is de facto for package management. So we will use it for our dependencies:

  "require-dev": {
    "phpunit/phpunit": "4.7.*",
    "sensio/generator-bundle": "~2.3",
    "behat/behat": "^3.1",
    "behat/symfony2-extension": "^2.1",
    "behat/mink": "^1.7",
    "behat/mink-extension": "^2.2",
    "behat/mink-browserkit-driver": "^1.3",
    "behat/mink-selenium2-driver": "^1.3"
  },

Then we need to update our project dependencies:

composer update

Setup context

Let’s create default context which will include all our basic functions. Names of methods are self documented so it won’t be hard to understand this code.

<?php
//features/context/DefaultContext.php
use Behat\Behat\Context\Context;
use Behat\MinkExtension\Context\RawMinkContext;
use Behat\Symfony2Extension\Context\KernelAwareContext;
 
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpKernel\KernelInterface;
 
abstract class DefaultContext extends RawMinkContext implements Context, KernelAwareContext
{
    /**
     * @var KernelInterface
     */
    protected $kernel;
 
    /**
     * {@inheritdoc}
     */
    public function setKernel(KernelInterface $kernel)
    {
        $this->kernel = $kernel;
    }
 
    /**
     * Returns Container instance.
     *
     * @return ContainerInterface
     */
    protected function getContainer()
    {
        return $this->kernel->getContainer();
    }
 
    /**
     * Get service by id.
     *
     * @param string $id
     *
     * @return object
     */
    protected function getService($id)
    {
        return $this->getContainer()->get($id);
    }
 
    /**
     * Generate url.
     *
     * @param string  $route
     * @param array   $parameters
     * @param Boolean $absolute
     *
     * @return string
     */
    protected function generateUrl($route, array $parameters = array(), $absolute = false)
    {
        return $this->locatePath($this->getService('router')->generate($route, $parameters, $absolute));
    }
 
    /**
     * Presses button with specified id|name|title|alt|value.
     */
    protected function pressButton($button)
    {
        $this->getSession()->getPage()->pressButton($this->fixStepArgument($button));
    }
 
    /**
     * Clicks link with specified id|title|alt|text.
     */
    protected function clickLink($link)
    {
        $this->getSession()->getPage()->clickLink($this->fixStepArgument($link));
    }
 
    /**
     * Fills in form field with specified id|name|label|value.
     */
    protected function fillField($field, $value)
    {
        $this->getSession()->getPage()->fillField($this->fixStepArgument($field), $this->fixStepArgument($value));
    }
 
    /**
     * Returns fixed step argument (with \\" replaced back to ").
     *
     * @param string $argument
     *
     * @return string
     */
    protected function fixStepArgument($argument)
    {
        return str_replace('\\"', '"', $argument);
    }
}

Next we need to create our context. Let’s name in FeatureContext for example. We should define all steps that we have in scenario and they can be reusable. Keep in mind that we have some steps defined in RawMinkContext. If you won’t find needed method there, you should write your custom steps. You can see examples below.

<?php
//features/bootstrap/FeatureContext.php
use Behat\Behat\Tester\Exception\PendingException;
use Behat\Behat\Context\Context;
use Behat\Behat\Context\SnippetAcceptingContext;
use Behat\Gherkin\Node\PyStringNode;
use Behat\Gherkin\Node\TableNode;
 
/**
 * Defines application features from the specific context.
 */
class FeatureContext extends DefaultContext implements Context, SnippetAcceptingContext
{
    /**
     * Initializes context.
     *
     * Every scenario gets its own context instance.
     * You can also pass arbitrary arguments to the
     * context constructor through behat.yml.
     */
    public function __construct()
    {
    }
 
    /**
     * @When I click on the link :arg1
     */
    public function iClickOnTheLink($link)
    {
        $this->clickLink($link);
    }
 
    /**
     * @When I fill in the following :arg1 in field :arg2
     */
    public function iFillInTheFollowing($value,$key)
    {
        $this->fillField($key,$value);
    }
}

Write scenario

Finally, we can write our scenario in human readable format and DRY way using Gherkin language. Note if you  @javascript notation then it will be executed using mink and driver. I use selenium driver in this example.

#features/post.feature
Feature: Post Creation
  Create post workflow using tags
  @javascript
  Scenario: Create post
    Given I am on "/"
    When I click on the link "Create Post"
    Then I should be on "/post/create"
    When I fill in the following "New Post" in field "Title"
    And I click on the link "Add a tag"
    When I fill in the following "New Tag" in field "Name"
    And I press "Submit"
    Then I should be on "/post/list"
    And I should see "New Post"
    And I should see "New Tag"

Install selenium

Download selenium standalone server http://www.seleniumhq.org/download/. You can have some problems with drivers on your system but it can be fixed easily by downloading needed driver for system.

java -jar selenium-server-standalone-version.jar #with default driver
java -jar selenium-server-standalone-version.jar -Dwebdriver.chrome.driver="/usr/local/share/chromedriver" #custom driver

Don’t forget to download chrome driver on your system if you’re using custom driver.

Run tests

Simply run:

vendor/bin/behat

Here we go. On the video below you can see how script opens session in browser and add post with tags in our application.

Application can be found on github: https://github.com/Infernosquad/stackoverflow-driven


About the Author / Artem Zhuravlev

Artem Zhuravlev. Web developer. Blog writer.

Need help with your website ? Contact with me by email infzanoza@gmail.com for services of experienced web developer.

Follow @infernosquad

LEAVE A COMMENT