title: Optimising behat test suite
body: <p>I have a test suite which has 20 feaure files and 100% MySQL CRUD operations are being carried out. It takes about 5 minutes to finish. If I did the test manually it would take about 7 minutes max. What I need to know is, what I need to do in order to optimise the whole process?</p>
  
  <p><strong>Note</strong>: ParallelRunnder <a href="https://github.com/shvetsgroup/ParallelRunner/issues/26" rel="nofollow">is not supported</a> for Behat 3 so it is out of scope for now!</p>
  
  <p>If you're going to suggest to use Behat 3, then please help me modifying my composer.json &amp; behat.yml files because when I do it myself and run bin/behat I get errors like:</p>
  
  <pre><code>`Behat\Symfony2Extension\Extension` extension file or class could not be located.
  `Behat\MinkExtension\Extension` extension file or class could not be located. 
  Unrecognized options "mink_driver" under "testwork.symfony2"
  Unrecognized options "context, paths" under "testwork" 
  </code></pre>
  
  <p>As you can see below, I use certain-ish versions numbers, no star signs.</p>
  
  <p><strong>CURRENT composer.json:</strong></p>
  
  <pre><code>"require": {
      "php": "&gt;=5.3.3",
      "symfony/symfony": "2.5.4",
      "doctrine/orm": "~2.2,&gt;=2.2.3",
      "doctrine/doctrine-bundle": "~1.2",
      "twig/extensions": "~1.0",
      "symfony/assetic-bundle": "~2.3",
      "symfony/swiftmailer-bundle": "~2.3",
      "symfony/monolog-bundle": "~2.4",
      "sensio/distribution-bundle": "~3.0",
      "sensio/framework-extra-bundle": "~3.0",
      "incenteev/composer-parameter-handler": "~2.0",
      "behat/behat": "2.5.3",
      "behat/behat-bundle": "1.0.0",
      "behat/symfony2-extension": "1.1.2",
      "behat/mink": "1.5.0",
      "behat/mink-extension": "~1.3",
      "behat/mink-selenium2-driver": "1.1.1",
      "behat/mink-goutte-driver": "1.0.9"
  },
  </code></pre>
  
  <p><strong>CURRENT behat.yml:</strong></p>
  
  <pre><code>default:
      context:
          class: FeatureContext
          parameters:
              output_path: %behat.paths.base%/build/behat/output/
              screen_shot_path: %behat.paths.base%/build/behat/screenshot/
      extensions:
          Behat\Symfony2Extension\Extension:
              mink_driver: true
              kernel:
                  env: test
                  debug: true
          Behat\MinkExtension\Extension:
              base_url: 'http://symfony.local/app_test.php/'
              files_path: %behat.paths.base%/build/dummy/
              javascript_session: selenium2
              browser_name: firefox
              goutte: ~
              selenium2: ~
      paths:
          features: %behat.paths.base%/src
          bootstrap: %behat.paths.features%/Context
  </code></pre>
  
  <p><strong>EDIT</strong>:</p>
  
  <p>I have 20 feature files and one scenario in each. For the CRUD operations:</p>
  
  <ul>
  <li>I have login method running in each scenario. Query runs against DB.</li>
  <li>Some scenarios do INSERT, some to UPDATE and some do DELETE.</li>
  <li>I'm using <code>pdo_mysql</code> as <code>database_driver</code></li>
  </ul>
  
  <p><strong>A part of my FeatureContext file:</strong></p>
  
  <pre><code>namespace Site\CommonBundle\Features\Context;
  
  use Behat\MinkExtension\Context\MinkContext;
  use Behat\Mink\Exception\UnsupportedDriverActionException;
  use Behat\Mink\Driver\Selenium2Driver;
  use Behat\Symfony2Extension\Context\KernelAwareInterface;
  use Symfony\Component\HttpKernel\KernelInterface;
  use Symfony\Component\Process\Process;
  
  /**
   * Class FeatureContext
   *
   * Parent to other FeatureContext files. It is used to avoid duplicated codes and all the
   * shared commons are kept here.
   *
   * @package Site\CommonBundle\Features
   */
  class FeatureContext extends MinkContext implements KernelAwareInterface
  {
      protected $kernel;
      protected $screenShotPath;
      protected $outputPath;
  
      /**
       * Parameter $parameters comes from behat.yml file.
       * @param array $parameters
       */
      public function __construct(array $parameters)
      {
          $this-&gt;outputPath = $parameters['output_path'];
          $this-&gt;screenShotPath = $parameters['screen_shot_path'];
      }
  
      /**
       * Helps to use doctrine and entity manager.
       * @param KernelInterface $kernelInterface Interface for getting Kernel.
       */
      public function setKernel(KernelInterface $kernelInterface)
      {
          $this-&gt;kernel = $kernelInterface;
      }
  
      /**
       * Without this, PhantomJs will fail if responsive design is in use.
       * @BeforeStep
       */
      public function resizeWindow()
      {
          $this-&gt;getSession()-&gt;resizeWindow(1440, 900, 'current');
      }
  
      /**
       * Take screen-shot when step fails. Works only with Selenium2Driver.
       *
       * @AfterStep
       * @param $event Current event.
       * @throws \Behat\Mink\Exception\UnsupportedDriverActionException
       */
      public function takeScreenshotAfterFailedStep($event)
      {
          if (4 === $event-&gt;getResult()) {
              $driver = $this-&gt;getSession()-&gt;getDriver();
  
              if (! ($driver instanceof Selenium2Driver)) {
                  throw new UnsupportedDriverActionException(
                      'Taking screen-shots is not supported by %s, use Selenium2Driver instead.',
                      $driver
                  );
  
                  return;
              }
  
              if (! is_dir($this-&gt;screenShotPath)) {
                  mkdir($this-&gt;screenShotPath, 0777, true);
              }
  
              $filename = sprintf(
                  '%s_%s_%s.%s',
                  $this-&gt;getMinkParameter('browser_name'),
                  date('Ymd') . '-' . date('His'),
                  uniqid('', true),
                  'png'
              );
  
              file_put_contents($this-&gt;screenShotPath . '/' . $filename, $driver-&gt;getScreenshot());
          }
      }
  
      /**
       * @When /^I login as "([^"]*)"$/
       * @param $type User role type.
       */
      public function iLoginAs($type)
      {
          $container = $this-&gt;kernel-&gt;getContainer();
          $userData = $container-&gt;getParameter('dummy_user');
  
          $this-&gt;visit('/login');
          $this-&gt;fillField('username', $userData[$type]['username']);
          $this-&gt;fillField('password', $userData[$type]['password']);
          $this-&gt;pressButton('_submit');
      }
      .........
  }
  </code></pre>