Archive | Behat RSS feed for this section

Automating Web Performance Data Collection with Behat and BrowserMob Proxy

30 Oct

BrowserMob Proxy is a utility which is used for capuring HTTP traffic and performance data from the browser. BrowserMob-Proxy adds in essential missing capabilities such as checking HTTP status codes and injecting headers for HTTP Basic Auth. Web Perfomance data can be manually captured by other tools like Firebug or Developers Tools. Using BrowserMob Proxy we can capture perfonace data in HAR format while running automated tests. There is lots of food to learn about BrowserMob on thier official website.

In this article, we will see how to integrate BrowserMob Proxy with Behat. In order to get started we need to install PHPBrowserMob package.

PHPBrowserMob

$ sudo pear channel-discover element-34.github.com/pear
$ sudo pear install -f element-34/PHPBrowserMobProxy
$ sudo pear install -f element-34/Requests

Download latest version of the BrowserMob Proxy from the site. You can launch BrowserMob proxy like this

$ cd browsermob-proxy-2.0-beta-6/
$ cd bin
$ sh browsermob-proxy -port 9090

You will see something like this:

$ sh browsermob-proxy -port 9090
INFO 10/30 21:29:50 o.b.p.Main           - Starting BrowserMob Proxy version 2.0-beta-6
INFO 10/30 21:29:51 o.e.j.u.log          - jetty-7.3.0.v20110203
INFO 10/30 21:29:51 o.e.j.u.log          - started o.e.j.s.ServletContextHandler{/,null}
INFO 10/30 21:29:52 o.e.j.u.log          - Started SelectChannelConnector@0.0.0.0:9090

This means, BrowserMob Proxy is running correcrtly.

Download and start selenium version 2.25.0. Note that, proxy won’t work for some version of selenium server. Better Download latest.

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

Now, We need to install Behat by following official doc Or just follow my previous post on Behat installtion with composer.

$ sudo mkdir Behat-BrowserMob
$ sudo chmod -R 777 Behat-BrowserMob
$ cd Behat-BrowserMob/
$ behat --init

Now create a feature file for exporting the performance data in the HAR format.

$ sudo vim BehatBrowserMob.feature
 Feature: BrowserMob Proxy with Behat
In order to check website performance
As a automated tester
I need to see network traffic captured in the HAR format

@javascript
Scenario: Behat Bowsermob
Given I setup BrowserMobProxy
And I Navigate to "http://www.facebook.com/"
When I export HAR
Then I should see network traffic in the HAR file

You need to include ‘PHPWebDriver‘ and ‘PHPBrowserMobProxy
We can implement the feature using following code :

<?php

use Behat\Behat\Context\ClosuredContextInterface,
Behat\Behat\Context\TranslatedContextInterface,
Behat\Behat\Context\BehatContext,
Behat\Behat\Exception\PendingException;
use Behat\Gherkin\Node\PyStringNode,
Behat\Gherkin\Node\TableNode;
use Behat\MinkExtension\Context\MinkContext;

require_once __DIR__ . '/PHPBrowserMobProxy/Client.php';
require_once __DIR__ . '/php-webdriver/PHPWebDriver/WebDriver.php';
require_once __DIR__ . '/php-webdriver/PHPWebDriver/WebDriverProxy.php';
require_once 'PHPUnit/Framework/Assert/Functions.php';
require_once 'PHPUnit/Autoload.php';

/**
* Features context.
*/
class FeatureContext extends BehatContext {

protected static $driver;
protected static $BrowserMob;
protected static $BrowserMobSession;
public $data;

/**
* Initializes context.
* Every scenario gets it's own context object.
*
* @param array $parameters context parameters (set them up through behat.yml)
*/
public function __construct(array $parameters) {

}

/**
* @BeforeScenario
*/
public function cleanup() {
$HARFile = "/tmp/BROWSERMOBHAR.php";
if (file_exists($HARFile)) {
echo "The file $HARFile exists, I am going to delete it \n";
unlink($HARFile);
}
}

/**
* @Given /^I setup BrowserMobProxy$/
*/
public function iSetupBrowsermobproxy() {
self::$driver = new PHPWebDriver_WebDriver();
self::$BrowserMob = new PHPBrowserMobProxy_Client("localhost:9090");
$additional_capabilities = array();
$webDriverProxy = new PHPWebDriver_WebDriverProxy();
self::$BrowserMob->new_har("google");
$webDriverProxy->httpProxy = self::$BrowserMob->url;
$webDriverProxy->add_to_capabilities($additional_capabilities);
$this->session = self::$driver->session('firefox', $additional_capabilities);
}

/**
* @Given /^I Navigate to "([^"]*)"$/
*/
public function iNavigateTo($url) {

$this->session->open($url);
}

/**
* @When /^I export HAR$/
*/
public function iExportHar() {
file_put_contents("/tmp/BROWSERMOBHAR.php", var_export(self::$BrowserMob->har, true));
}

/**
* @Then /^I should see network traffic in the HAR file$/
*/
public function iShouldSeeNetworkTrafficInTheHarFile() {
assertFileExists('/tmp/BROWSERMOBHAR.php');
}

}

Now, run ‘behat’ and watch the test running in the Browser. You will find data stored in the ‘/tmp/BROWSERMOBHAR’ file. You can use HAR viewer to see performance data in fancy way !

There are number of possibilities you can use this data. Here is best article which describe use of HAR file.

  • Calculate Load time.
  • Set/Get HTTP Headers during your tests
  • Capture performance data with HAR files.
  • Simulate network traffic and latency
  • Rewrite HTTP requests and respones

SourcCode on GitHub:

Source Code is available on GitHub repo ‘Behat-BrowserMobProxy‘ . Just give it a try !

Final Thoughts:

Combination of Behat, WebDriver and BrowserMob Proxy can be used for capturing the network trafic while running automated tests. We can use HAR files as per our need eg. Calculate Page load times, Page performance analysis etc etc..

Enjoy ‘MinkExtension’ for Behat

7 May

Note : This post may not work with recent Behat. Please use and my  Github repo for to get it working without any issue https://github.com/Shashikant86/BehatDemo

MinkExtension‘ has been just released which has additional services for Behat. This extension has ‘Mink’ instance for your ‘FeatureContext’ and ‘SubContext’. UI testers would be happy now, as they don’t need to create Mink instance every time in order to use Mink API’s.

Well, in order to use ‘MinkExtension’ you need latest Behat and Mink versions (Behat 2.4+ and Mink 1.4+). Don’t worry so much about the versions,  creator of Behat has taken care of all this with composer.

Ok. Let’s clone the MinkExtenion-Example repository from GitHub. See, everything is mentioned in README file.

git clone https://github.com/Behat/MinkExtension-example.git
Cloning into MinkExtension-example...
remote: Counting objects: 31, done.
remote: Compressing objects: 100% (16/16), done.
remote: Total 31 (delta 13), reused 31 (delta 13)
Receiving objects: 100% (31/31), 4.43 KiB, done.
Resolving deltas: 100% (13/13), done.

Navigate to directory & Get the composer and Install dependencies

cd MinkExtension-example
curl http://getcomposer.org/installer | php
moonstar:MinkExtension-example sjagtap$ curl http://getcomposer.org/installer | php
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
Dload  Upload   Total   Spent    Left  Speed
100  7438  100  7438    0     0  52386      0 --:--:-- --:--:-- --:--:--  105k
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: /Users/sjagtap/MinkExtension-example/composer.phar
Use it: php composer.phar

Install Dependencies

php composer.phar install
oonstar:MinkExtensionTest sjagtap$ php composer.phar install
Installing dependencies
- Package symfony/yaml (dev-master)
Cloning 48fcffece8de2ade6f6dbc909f22444356b7659f

- Package symfony/translation (dev-master)
Cloning 34b64346b24024d54f42877b7c34ccc05ff1eaa8

- Package symfony/event-dispatcher (dev-master)
Cloning 0c1ae4898196f5e96b79028d8d2f35de4b584659

- Package symfony/dependency-injection (dev-master)
Cloning b01877ddbde08c1eded2502a6fdce8dbde89bd35

- Package symfony/config (dev-master)
Cloning 2f2fb45da8100bc03d2d9cbcd75e3ff36e325b89

- Package symfony/finder (2.0.x-dev)
Cloning v2.0.13

- Package symfony/css-selector (2.0.x-dev)
Cloning v2.0.12

- Package symfony/dom-crawler (2.0.x-dev)
Cloning v2.0.13

- Package symfony/browser-kit (2.0.x-dev)
Cloning v2.0.12

- Package symfony/process (dev-master)
Cloning 1bc1398d51180fd2aeded9c44f4d7b73bea817cd

- Package symfony/console (dev-master)
Cloning 8d58af16c425977018293eb0a1570c9629b37994

- Package behat/gherkin (2.2.x-dev)
Cloning ada4bda5823ffe1df8228e9dddefa38d6420f983

- Package zendframework/zend-registry (2.0.0beta3)
Downloading: 100%

- Package zendframework/zend-loader (2.0.0beta3)
Downloading: 100%

- Package zendframework/zend-stdlib (2.0.0beta3)
Downloading: 100%

- Package zendframework/zend-validator (2.0.0beta3)
Downloading: 100%

- Package zendframework/zend-http (2.0.0beta3)
Downloading: 100%

- Package zendframework/zend-uri (2.0.0beta3)
Downloading: 100%

- Package facebook/php-webdriver (master-dev)
Cloning master

- Package fabpot/goutte (master-dev)
Cloning master

- Package behat/mink-extension (dev-master)
Cloning cd8eb2c85859f7d5e88e5787d4e171eaa52002eb

- Package behat/mink (v1.4.0beta2)
Downloading: 100%

- Package behat/behat (v2.4.0beta3)
Downloading: 100%

symfony/event-dispatcher suggests installing symfony/http-kernel (dev-master)
behat/mink suggests installing behat/sahi-client (Sahi-Client is needed to use the SahiDriver)
behat/mink suggests installing alexandresalome/php-selenium (Php-Selenium is needed to use the SeleniumDriver)
behat/behat suggests installing behat/yii-extension (for integration of with Yii framework)
Writing lock file
Generating autoload files

Now Run Behat command,

./bin/behat

Look, if you still using PHP5.3.x Then you will get

moonstar:MinkExtension-example sjagtap$ ./bin/behat
PHP Parse error:  syntax error, unexpected T_USE, expecting T_FUNCTION in /Users/sjagtap/MinkExtension-example/features/bootstrap/TraitedFeatureContext.php on line 5
PHP Stack trace:
PHP   1. {main}() /Users/sjagtap/MinkExtension-example/vendor/behat/behat/bin/behat:0
PHP   2. Symfony\Component\Console\Application-&amp;gt;run() /Users/sjagtap/MinkExtension-example/vendor/behat/behat/bin/behat:27
PHP   3. Behat\Behat\Console\BehatApplication-&amp;gt;doRun() /Users/sjagtap/MinkExtension-example/vendor/symfony/console/Symfony/Component/Console/Application.php:106
PHP   4. Symfony\Component\Console\Application-&amp;gt;doRun() /Users/sjagtap/MinkExtension-example/vendor/behat/behat/src/Behat/Behat/Console/BehatApplication.php:93
PHP   5. Symfony\Component\Console\Command\Command-&amp;gt;run() /Users/sjagtap/MinkExtension-example/vendor/symfony/console/Symfony/Component/Console/Application.php:193
PHP   6. Behat\Behat\Console\Command\BaseCommand-&amp;gt;initialize() /Users/sjagtap/MinkExtension-example/vendor/symfony/console/Symfony/Component/Console/Command/Command.php:225
PHP   7. Behat\Behat\Console\Processor\AggregateProcessor-&amp;gt;process() /Users/sjagtap/MinkExtension-example/vendor/behat/behat/src/Behat/Behat/Console/Command/BaseCommand.php:55
PHP   8. Behat\Behat\Console\Processor\LocatorProcessor-&amp;gt;process() /Users/sjagtap/MinkExtension-example/vendor/behat/behat/src/Behat/Behat/Console/Processor/AggregateProcessor.php:57

This is time to update your PHP version. If you still want run features with same PHP version, then comment out/ remove everything from ‘TraitedFeatureContext.php’ which is for PHP5.4

Now,  Start Selenium server & Run behat with ‘inheritance’  or  ‘subcontext’ profile.

./bin/behat -p=inheritance
./bin/behat -p=subcontexts

You will see test running with headless as well as with browser. You will see output like this

moonstar:MinkExtension-example sjagtap$ ./bin/behat -p=subcontexts
Feature: Search
  In order to see a word definition
  As a website user
  I need to be able to search for a word

  Scenario: Searching for a page that does exist               # features/search.feature:6
    Given I am on &amp;quot;/wiki/Main_Page&amp;quot;                            # Behat\MinkExtension\Context\MinkContext::visit()
    When I fill in &amp;quot;search&amp;quot; with &amp;quot;Behavior Driven Development&amp;quot; # Behat\MinkExtension\Context\MinkContext::fillField()
    And I press &amp;quot;searchButton&amp;quot;                                 # Behat\MinkExtension\Context\MinkContext::pressButton()
    Then I should see &amp;quot;agile software development&amp;quot;             # Behat\MinkExtension\Context\MinkContext::assertPageContainsText()

  Scenario: Searching for a page that does NOT exist           # features/search.feature:12
    Given I am on &amp;quot;/wiki/Main_Page&amp;quot;                            # Behat\MinkExtension\Context\MinkContext::visit()
    When I fill in &amp;quot;search&amp;quot; with &amp;quot;Glory Driven Development&amp;quot;    # Behat\MinkExtension\Context\MinkContext::fillField()
    And I press &amp;quot;searchButton&amp;quot;                                 # Behat\MinkExtension\Context\MinkContext::pressButton()
    Then I should see &amp;quot;Search results&amp;quot;                         # Behat\MinkExtension\Context\MinkContext::assertPageContainsText()

  @javascript
  Scenario: Searching for a page with autocompletion           # features/search.feature:19
    Given I am on &amp;quot;/wiki/Main_Page&amp;quot;                            # Behat\MinkExtension\Context\MinkContext::visit()
    When I fill in &amp;quot;search&amp;quot; with &amp;quot;Behavior Driv&amp;quot;               # Behat\MinkExtension\Context\MinkContext::fillField()
    And I wait for the suggestion box to appear                # SubcontextedFeatureContext::iWaitForTheSuggestionBoxToAppear()
    Then I should see &amp;quot;Behavior Driven Development&amp;quot;            # Behat\MinkExtension\Context\MinkContext::assertPageContainsText()

3 scenarios (3 passed)
12 steps (12 passed)
0m14.59s

What’s new for Testers in MinkExtension?

  • You will get Mink instance in your ‘FeatureContext’ as well as ‘SubContexts’ classes.
  • You can extend Base Contextfile to MinkContext as shown in below. For other context you need to extend from RawMinkContext
class MyContext extends Behat\MinkExtension\Context\MinkContext
  • You can use MinkExtension as a SubContext in your files like this:
class SubcontextedFeatureContext extends Behat\Behat\Context\BehatContext
{
public function __construct()
{
$this-&gt;useContext('mink', new Behat\MinkExtension\Context\MinkContext);
}

This extension is a base for future extensions. We can extend Behat/Mink with any other services testing services like SauceLabs and many more.  This feature will definitely useful for Web Testers using Behat and Mink for browser automation. SauceLabs extension is on it’s way..  stay tuned 🙂

Happy BDD !!!

Adding More Sauce To Behat

24 Apr

 

Note : This post may not work with recent Behat. Please use and my  Github repo for to get it working without any issue https://github.com/Shashikant86/BehatDemo

 

Further to my previous post regarding ‘Behat-Sauce’ integration, ‘Adding Sauce To Behat‘, I am glad to know that there is another Behat and SauceLabs integration from Laura Beth. Thanks a lot Laura for that excellent effort.

On the occasion of Selenium Conference, I met with Noah Sussman talking about “Selenium In the Enterprise: What Went Right, What Went Wrong (So Far)” and one of his slides indicated that, team using Behat and Mink for the functional testing at Etsy. Noah then introduced me to Laura Beth who setup Behat/Mink and SauceLabs integration. Behat-Sauce configuration by Laura Beth is very easy to use.

Now, we will see this in action.

Behat Installation 

Create a ‘Demo’ directory  and Clone the repository from Laura Beth’s GitHub account

moonstar:~ sjagtap$ mkdir Demo
moonstar:~ sjagtap$ cd Demo
moonstar:Demo sjagtap$ git clone https://github.com/elblinkin/Behat-Sauce.git
Cloning into Behat-Sauce...
remote: Counting objects: 178, done.
remote: Compressing objects: 100% (105/105), done.
remote: Total 178 (delta 50), reused 166 (delta 38)
Receiving objects: 100% (178/178), 58.74 MiB | 503 KiB/s, done.
Resolving deltas: 100% (50/50), done.

Ok, you got all the code in ‘Behat-Sauce’ directory. Now you need to download dependencies for Behat. Navigate to Behat-Sauce and download composer.

moonstar:Behat-Sauce sjagtap$ wget  http://getcomposer.org/composer.phar
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  442k  100  442k    0     0   988k      0 --:--:-- --:--:-- --:--:-- 1436k

Now, update ‘composer.phar’ file. It will download all dependencies.

moonstar:Behat-Sauce sjagtap$ php composer.phar update
Updating dependencies
  - Package symfony/yaml (dev-master)
    Cloning 52807f723e8a9743852c2105f11bd01c5af7f977

  - Package symfony/translation (dev-master)
    Cloning cac219a6dee410df41ac5dae15553313f48f1fd1

  - Package symfony/event-dispatcher (dev-master)
    Cloning b98d68d3b8513c62d35504570f09e9d3dc33d083

  - Package symfony/dependency-injection (dev-master)
    Cloning 61e664ab2eead27d83ebb45d2bf83dd55ef509a8

  - Package symfony/config (dev-master)
    Cloning 175adaf7dbed4ad5350e75a4fd3de39480df6cf3

  - Package symfony/console (dev-master)
    Cloning f354e1e5d59261ae03c0fc768bfa4043c0e6ab9c

  - Package symfony/process (dev-master)
    Cloning 3f95a0126588f00d70e745c1ef96631fb10c3a8e

  - Package symfony/css-selector (dev-master)
    Cloning dd695aadd80d8e6e726a7a050535c04325cefa02

  - Package symfony/dom-crawler (dev-master)
    Cloning 69b857977d96e4c726be5524fa00370aef5e9b20

  - Package symfony/browser-kit (dev-master)
    Cloning f03173e232da5d84eb799cad5d57354e6541b0f8

  - Package symfony/finder (dev-master)
    Cloning 5b8658e52eaf424fe943a5857e2404ce95c3b90e

  - Package behat/mink (dev-master)
    Cloning v1.3.3

  - Package behat/behat (dev-master)
    Cloning d8ff3fe0f8c44c664c5eebbb6b972bbdff70c166

  - Package alexandresalome/php-selenium (master-dev)
    Cloning master

  - Package behat/gherkin (v2.1.1)
    Downloading: 100%

symfony/translation suggests installing symfony/config (dev-master)
symfony/translation suggests installing symfony/yaml (dev-master)
symfony/event-dispatcher suggests installing symfony/dependency-injection (dev-master)
symfony/event-dispatcher suggests installing symfony/http-kernel (dev-master)
symfony/dependency-injection suggests installing symfony/yaml (dev-master)
symfony/dependency-injection suggests installing symfony/config (dev-master)
symfony/dom-crawler suggests installing symfony/css-selector (dev-master)
symfony/browser-kit suggests installing symfony/process (dev-master)
Writing lock file
Generating autoload files

You have just installed Behat and all dependencies. Now initialize project by running ‘bin/behat-sauce –init’ command.

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --init
+d features - place your *.feature files here
+d features/bootstrap - place bootstrap scripts and static files here
+f features/bootstrap/FeatureContext.php - place your feature related code here
+d config - edit you config settings here
+f /Users/sjagtap/Demo/Behat-Sauce/configbehat.yml - place your feature related code here

Once you initialized ‘Behat’. It will ‘features’ and ‘features/bootstrap’ directories and ‘features/bootstrap/FeatureContext.php’ file for you.

Feature file

You can also see ‘config’ directory with ‘behat.yml’ file for you. You need to add SauceLabs ‘Username’ and API key to the ‘behat.yml’.

Now write a simple feature file and save it to ‘features’ directory.

Feature: wikiSearch
  In order to search information on wiki
  As a Wiki user
  I want to get sensible results from site

  @javascript
  Scenario Outline: Search Keywords on wiki
    Given I am on "/"
    And I fill in searchBox with "<input type="text" />"
    When I press search button
Then I should see "<output>"

 Examples:
 | input | output |
 | London | lʌndən/ |

Step Definition

You need implement step definitions using Mink API’s. You feature context file will look like this now.

<!--?php use Behat\Behat\Context\ClosuredContextInterface,     Behat\Behat\Context\TranslatedContextInterface,     Behat\Behat\Exception\PendingException; use Behat\Gherkin\Node\PyStringNode,     Behat\Gherkin\Node\TableNode; use Behat\Sauce\Context\SauceContext; /**  * Features context.  */ class FeatureContext extends SauceContext {     /**      * Initializes context.      * Every scenario gets it's own context object.      *      * @param   array   $parameters     context parameters (set them up through behat.yml)      */     public function __construct(array $parameters) {         parent::__construct($parameters);     } /**      * @Given /^I fill in searchBox with "([^"]*)"$/      */     public function iFillInSearchboxWith($input)     {         $this--->fillField("searchInput",$input);
    }

    /**
     * @When /^I press search button$/
     */
    public function iPressSearchButton()
    {
        $this->getMink()->getSession()->getDriver()->click("//*[@id='searchButton']");
         $this->getMink()->getSession()->wait("3000");
    }
}

Well, now you are ready to run your tests on SauceLabs just by running

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce

You will see test running on the SauceLabs. Once tests finished running, you will see output like this:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce
Feature: wikiSearch
  In order to search information on wiki
  As a Wiki user
  I want to get sensible results from site

  @javascript
  Scenario Outline: Search Keywords on wiki # features/wikiSearch.feature:7
    Given I am on "/"                       # FeatureContext::visit()
    And I fill in searchBox with "<input type="text" />"  # FeatureContext::iFillInSearchboxWith()
    When I press search button              # FeatureContext::iPressSearchButton()
Then I should see "<output>" # FeatureContext::assertPageContainsText()

 Examples:
 | input | output |
 | London | lʌndən/ |

1 scenario (1 passed)
4 steps (4 passed)
1m8.949s

You can watch video of the test here

As per Laura Beth, default arguments are:

 --browser              SauceLabs browser name.  Default is:  firefox
 --browser-version      SauceLabs browser version.  Default is:  7
 --os                   SauceLabs operating system.  Default is:  Windows 2003

Now let’s run our tests on different browser and different OS:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --browser="firefox" --browser-version="3.6" --os="Linux"

You will see same output:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --browser="firefox" --browser-version="3.6" --os="Linux"
Feature: wikiSearch
  In order to search information on wiki
  As a Wiki user
  I want to get sensible results from site

  @javascript
  Scenario Outline: Search Keywords on wiki # features/wikiSearch.feature:7
    Given I am on "/"                       # FeatureContext::visit()
    And I fill in searchBox with "<input type="text" />"  # FeatureContext::iFillInSearchboxWith()
    When I press search button              # FeatureContext::iPressSearchButton()
Then I should see "<output>" # FeatureContext::assertPageContainsText()

 Examples:
 | input | output |
 | London | lʌndən/ |

1 scenario (1 passed)
4 steps (4 passed)
1m38.828s

Video of the tests can be found here

Sauce-Connect:

You can also start Sauce-Connect tunnel with the same credentials that you provided in config/behat.yml file

bin/behat-sauce --tunnel

You will see something like this:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --tunnel
[-u, Shashikant86, -k, API Key, -d, sauce-connect.proxy, -s, 127.0.0.1, -p, 80, --ssh-port, 443, -b, --rest-url, https://saucelabs.com/rest/v1, --se-port, 4445, --squid-opts, ]
* Debug messages will be sent to sauce_connect.log
2012-04-24 17:27:32.354:INFO::jetty-7.x.y-SNAPSHOT
2012-04-24 17:27:32.439:INFO::Started SelectChannelConnector@0.0.0.0:50044
.---------------------------------------------------.
| Have questions or need help with Sauce Connect? |
| Contact us: http://support.saucelabs.com/forums |
| Terms of Service: http://saucelabs.com/tos |
-----------------------------------------------------
2012-04-24 17:27:32,509 - / Starting \
2012-04-24 17:27:32,513 - Please wait for "You may start your tests" to start your tests.
2012-04-24 17:27:32,526 - Forwarding: ['sauce-connect.proxy']:['80'] -> 127.0.0.1:['50044']
2012-04-24 17:27:32,538 - Succesfully connected to local server 127.0.0.1:50044 in 6ms
2012-04-24 17:27:33,201 - {"squid_config":[""],"use_caching_proxy":true,"fast_fail_regexps":[""],"ssh_port":443,"metadata":{"PythonVersion":"2.5.1","OwnerHost":"127.0.0.1","Release":"3.0-r18","OwnerPorts":["50044"],"Ports":["80"],"Platform":"Java-1.6.0_26-Java_HotSpot-TM-_64-Bit_Server_VM,_20.1-b02-383,_Apple_Inc.-on-Mac_OS_X-10.7.1-x86_64","Build":"26","ScriptRelease":26,"ScriptName":"sauce_connect"},"use_kgp":true,"domain_names":["sauce-connect.proxy"]}
2012-04-24 17:27:33,486 - Tunnel remote VM is provisioned (a86bd10139b8464081e185b016b6579d)
2012-04-24 17:27:33,756 - Tunnel remote VM is new ..
2012-04-24 17:27:37,068 - Tunnel remote VM is deploying ..
2012-04-24 17:27:40,440 - Tunnel remote VM is booting ..
2012-04-24 17:28:06,611 - Tunnel remote VM is running at maki10148.miso.saucelabs.com
2012-04-24 17:28:06,723 - Succesfully connected to local server 127.0.0.1:50044 in 0ms
2012-04-24 17:28:06,729 - Starting connection to tunnel host...
2012-04-24 17:28:06,732 - Connecting to tunnel host maki10148.miso.saucelabs.com as Shashikant86
2012-04-24 17:28:06,994 - Forwarding Selenium with ephemeral port 50478
2012-04-24 17:28:06.996:INFO::jetty-7.x.y-SNAPSHOT
2012-04-24 17:28:06.998:INFO::Started SelectChannelConnector@0.0.0.0:4445
2012-04-24 17:28:07,000 - Selenium HTTP proxy listening on port 4445
2012-04-24 17:28:07,855 - Successful handshake with Sauce Connect server
2012-04-24 17:28:08,109 - Tunnel host version: 0.1.0, remote endpoint ID: 2851094ae70e4e949a0e96c8ca453748
2012-04-24 17:28:08,112 - Connected! You may start your tests.

Sauce connect is used for testing internal site.

Test Locally:

Well, if you don’t want to waste sauceLabs minutes. You can run your test locally:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --local

You will see tests running on local machine with Firefox and output is same:

moonstar:Behat-Sauce sjagtap$ ./bin/behat-sauce --local
Feature: wikiSearch
  In order to search information on wiki
  As a Wiki user
  I want to get sensible results from site

  @javascript
  Scenario Outline: Search Keywords on wiki # features/wikiSearch.feature:7
    Given I am on "/"                       # FeatureContext::visit()
    And I fill in searchBox with "<input type="text" />"  # FeatureContext::iFillInSearchboxWith()
    When I press search button              # FeatureContext::iPressSearchButton()
Then I should see "<output>" # FeatureContext::assertPageContainsText()

 Examples:
 | input | output |
 | London | lʌndən/ |

1 scenario (1 passed)
4 steps (4 passed)
0m16.109s

Contribution:

Well, I have forked repository and started implementing full scale SauceLabs grid which support all browsers &  OS combination. I am also trying to plug the features on continuous integration server like Jenkins. If you also wish to contribute then fork “Behat-Sauce”

Source code:

Code for the above example can be found “Behat-Sauce-Demo” repository.

Conclusion:

Believe me, this is simply awesome. Thanks again Laura Beth.

Happy BDD !!

PHPUnit + Behat/Mink + Page Object: The Rockstar Combination of Testing

7 Apr

Last month, we had discussion about implementing page object pattern in Behat/Mink framework at London Behat Users meetup . Page object pattern is a cool way to make tests maintainable, reusable and readable. Everyone was interested to know more about Page Object Pattern.

In this short tutorial, we will implement Mink and PHPUnit  combination for functional testing. Mink and PHPUnit combined with Pageness (Page Object) can be used for maintainable and readable tests. Mink is a web acceptance testing framework for PHP application. Mink has clean API’s which allows browsers emulation and browser controls. Mink has headless browser emulators as well as browser controls which covers all browsers interactions. PHPUnit is testing framework for PHP applications.

Installations

Lets start with some installations assuming PHP, Pear package is already installed.

Install PHPUnit

Now, upgrade pear package & install PHPUnit

$ pear update-channels
$ sudo pear channel-discover pear.phpunit.de
$ sudo pear channel-discover pear.symfony-project.com
$ pear channel-discover components.ez.no
$ sudo pear install –alldeps phpunit/PHPUnit
$ phpunit --version

Install Behat/Mink

$ pear channel-discover pear.symfony.com
$ pear channel-discover pear.behat.org
$ pear install behat/mink

Mink is ready to use just including in PHP classes.

require_once 'mink/autoload.php';

PHPUnit-Mink Framework on GitHub

PHPUnit-Mink framework designed to use combination of PHPUnit, Mink and Page Object Pattern to write functional tests with various browser emulators like Goutte, Selenium, Sahi and WebDriver. PHPUnit-Mink Framework has used Mink and PHPUnit to write tests. Driver support for Selenium, Sahi, WebDriver for browser emulation. Test Report Generation which can plugged in Continuous Integration server. Page Objects which can be used directly in tests. Abstracted common elements up in the framework in order to make it maintainable.

How to use:

  • Clone GitHub Repository
$git clone git@github.com:Shashi-ibuildings/PHPUnit-Mink.git
$cd PHPUnit-Mink
  • Start your Driver

Sahi Driver :

Download sahi zip file from SourceForge

Now launch Sahi Server using command below:

$ cd /path/to/sahi
$ cd userdata/bin
$./start_sahi.sh 

Selenium Driver:

You need to download selenium server jar file and execute following command:

$ cd /path/to/selenium-server
$java -jar selenium-server-standalone-2.20.0.jar 

In this tutorial, we are using sahi driver.

  • Now run tests using ANT
$cd /path/to/PHPUnit-Mink
$ant Mink

Directory structure

  1. conf    : YAML files can be used with Behat
  2. core    : Abstracted common elements/ methods
  3. Page   : Page objects (reusable Methods for page)
  4. report :  Generate Junit, Agile doc reports
  5. tests    :  PHPUnit tests using Mink Api’s

Don’t forget to include Mink and PHPUnit in Test like this:

<?php
require_once 'mink/autoload.php';
use Behat\Mink\Mink,
Behat\Mink\PHPUnit\TestCase;

Page Objects Pattern

There are some areas within application UI where your test interacts with. These areas can be identified by their functionality, they offer e.g login, registration, search etc. Page object pattern models as a object within you test code. While writing tests, we just need to create an object of the page and access methods and variables withing that page objects. This approach is useful when UI changes, we need to make changes in page objects not in the tests. Tests become readable and maintainable using page objects.

Page objects classes generally:

  1. Set of public methods that page offer which can be reused later.
  2. don’t make any assertion. Assertions can be added later into tests not in the page objects
  3. checks if user is on the same page that page object is created.
  4. don’t represent entire page but some important functions of that particular page.

GitHub & Other sources of Page object pattern

Read more about page object on  google wiki. There are couple of GitHub repositories that explains page object pattern, Saunter and pelenium

Writing Page Objects:

Common methods can be abstracted in the ‘page’ directory. You can specify driver of your choice. Now we have test with Sahi session. Example page looks like this

<?php
require_once 'mink/autoload.php';
use Behat\Mink\Mink,
Behat\Mink\PHPUnit\TestCase;
require_once 'core/core_PHPUnitMink_CommonElementFunctions.php';
class page_search extends TestCase
{
function search($input)
{
$this->getSession('sahi')->getPage()->fillField("searchInput",$input);
$this->getMink()->getSession('sahi')->getDriver()->click("//*[@id='searchButton']");
$this->getMink()->getSession('sahi')->wait("3000");
}
}
?

Using Page Objects in Tests

You can use pages just by creating new objects and accessing variables,methods in the test. Example of test looks like this

<?php
class wikiSearchTest extends core_PHPUnitMink_CommonElementFunctions
{
protected static $mink;</pre>
public function testwikiSearchsingle()
 {
 $page = new page_search($this):
 $page->visit();
 $page->search(“mumbai”);
<pre>assertEquals(“Mumbai”, $page->findFirstHeading()));
}

Writing Data-Driven Tests

You can write data driven tests by using PHPUnit and Mink combination. Data can be placed in CSV or in an array. Example data-driven test looks like this

<?php
class wikiSearchTest extends core_PHPUnitMink_CommonElementFunctions
{
protected static $mink;
function searchData() {
return array(
array('london','London'),
array('newyork','New York')
);
}
/**
*
* @param &lt;type&gt; $searchfor
* @param &lt;type&gt; $expectedResult
* @dataProvider searchData
*/

public function testwikiSearchMultiple($input,$output)
{
$this->getSession('sahi')
->visit('http://en.wikipedia.org/wiki/Main_Page');
$this->getSession('sahi')->getPage()->fillField("searchInput",$input);
$this->getMink()->getSession('sahi')->getDriver()->click("//*[@id='searchButton']");
$this->getMink()->getSession('sahi')->wait("3000");
assertEquals($output, $this->getMink()->getSession('sahi')->getDriver()->getText(".//*[@id='firstHeading']/span"));
}

}

Starting Engines

Before running tests, you need to start Mink drivers, here we are using Sahi. You can update tests to run Selenium driver. Launch driver from command line like this:

  • Sahi : Navigate to Sahi directory and run:
moonstar:~ sjagtap$ cd sahi/userdata/bin/
moonstar:bin sjagtap$ ./start_sahi.sh
--------
SAHI_HOME: ../..
SAHI_USERDATA_DIR: ../../userdata
SAHI_EXT_CLASS_PATH:
--------
Sahi properties file = /Users/sjagtap/sahi/config/sahi.properties
Sahi user properties file = /Users/sjagtap/sahi/userdata/config/userdata.properties
Added shutdown hook.
&gt;&gt;&gt;&gt; Sahi started. Listening on port: 9999
&gt;&gt;&gt;&gt; Configure your browser to use this server and port as its proxy
&gt;&gt;&gt;&gt; Browse any page and CTRL-ALT-DblClick on the page to bring up the Sahi Controller
-----
Reading browser types from: /Users/sjagtap/sahi/userdata/config/browser_types.xml
-----
  • Selenium
moonstar:downloads sjagtap$ java -jar selenium-server-standalone-2.20.0.jar
Apr 7, 2012 3:34:19 PM org.openqa.grid.selenium.GridLauncher main
INFO: Launching a standalone server
1 [main] INFO org.openqa.selenium.server.SeleniumServer - Java: Apple Inc. 20.1-b02-383
1 [main] INFO org.openqa.selenium.server.SeleniumServer - OS: Mac OS X 10.7.1 x86_64
8 [main] INFO org.openqa.selenium.server.SeleniumServer - v2.20.0, with Core v2.20.0. Built from revision 16008
131 [main] INFO org.openqa.selenium.server.SeleniumServer - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
132 [main] INFO org.openqa.jetty.http.HttpServer - Version Jetty/5.1.x
132 [main] INFO org.openqa.jetty.util.Container - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
133 [main] INFO org.openqa.jetty.util.Container - Started HttpContext[/selenium-server,/selenium-server]
133 [main] INFO org.openqa.jetty.util.Container - Started HttpContext[/,/]
273 [main] INFO org.openqa.jetty.util.Container - Started org.openqa.jetty.jetty.servlet.ServletHandler@62f47396
273 [main] INFO org.openqa.jetty.util.Container - Started HttpContext[/wd,/wd]
279 [main] INFO org.openqa.jetty.http.SocketListener - Started SocketListener on 0.0.0.0:4444
279 [main] INFO org.openqa.jetty.util.Container - Started org.openqa.jetty.jetty.Server@4a79717e

Running Tests with PHPUnit

Now you can run wikisearch test with PHPUnit like this :

moonstar:PHPUnit-Mink sjagtap$ phpunit tests/wikiSearchTest.php

Temporary SauceLabs fork 3.5.24 of PHPUnit by Sebastian Bergmann. Supports parallel testing. Becomes obsolete when PHPUnit 3.7.0 is released.

...

Time: 33 seconds, Memory: 11.25Mb

OK (3 tests, 3 assertions)

Running Tests with Ant

You can run tests using apache ANT. Navigate to project root directory (PHPUnit-Mink) and run an

moonstar:PHPUnit-Mink sjagtap$ ant Mink
Buildfile: /Users/sjagtap/PHPUnit-Mink/build.xml
[delete] Deleting directory /Users/sjagtap/PHPUnit-Mink/report
[mkdir] Created dir: /Users/sjagtap/PHPUnit-Mink/report

Mink:
[exec]
[exec]
[exec]
[exec]
[exec] Temporary SauceLabs fork 3.5.24 of PHPUnit by Sebastian Bergmann. Supports parallel testing. Becomes obsolete when PHPUnit 3.7.0 is released.
[exec]
[exec] ....
[exec]
[exec] Time: 45 seconds, Memory: 11.75Mb
[exec]
OK (4 tests, 4 assertions)

BUILD SUCCESSFUL
Total time: 46 seconds
moonstar:PHPUnit-Mink sjagtap$ 

Once all tests finished running, you will see build successful message. This build can be easily plugged into Continuous Integration server like Jenkins.

Conclusion:

Functional testing become much easier with use of Mink with PHPUnit. Page Object pattern can be used with PHPUnit-Mink to make tests reusable and readable.

You can find source code on GitHub PHPUnit-Mink repository. Happy PHP Testing !

Behat-SauceLabs Integration on GitHub

17 Mar

Behat is a new generation Behavior Driven Development tool for PHP applications. Behat is inspired by Ruby’s Cucumber. Behat can be used for web acceptance testing by using Mink. Mink uses browser emulators like Selenium, Sahi, WebDriver to launch browser.

SauceLabs is cloud testing service which allow selenium based tests into cloud machine with different browser combination. Create an account with Saucelabs and you will definitely love it

To install and setup Behat project, read SauceLabs blog ‘Adding Sauce To Behat‘.

Let’s directly move on to code. I assume you have installed Behat and Mink as per the blog ‘Adding Sauce To Behat’.

You can use code available on GitHub project ‘Behat-Sauce‘ directly into your project.

Requirement:

*Behat/Mink Installed

*Ant

*SauceLabs Account (Username and API Key)

*Jenkins (optional)

How to use?

* Clone the repository from my GitHub

   
$ git clone git@github.com:Shashi-ibuildings/Behat-Sauce.git
$ cd /path to/Behat-Sauce 

* Edit ‘Sauce.yml’ file in order to specify your username and API key.

* Now, Run ANT command to execute feature on sauce Labs

   
$ ant runSauce 

* Once All tests executed see the reports generated in ‘report/report.html’ file.

*  Use it in your project by updating ‘behat.yml’ and ‘sauce.yml’. Change Base url to your application url.

* Write and implement features in ‘features’ directory.

You can setup your Jenkins Continuous Integration server by following the blog post ‘Adding Sauce To Behat’

Don’t invest your time/money and effort in setting up different machine/browser combinations for cross browser testing. Better to use SauceLabs.

Any questions? Let me know.

Behat Meetup in a nutshell

17 Feb

Note : This post may not work with recent Behat. Please use and my  Github repo for to get it working without any issue https://github.com/Shashikant86/BehatDemo

 

On Feb 15, we had a great evening at Ibuildings, London office. We organized the first ever Behat meetup in the United Kingdom. A group  called “London Behat Users” organized an event to demonstrate Behavior Driven Development for the PHP developers and testers who wish to get started with Behat.

Behat is an amazing BDD framework for PHP developers which works exactly the same as Cucumber. Assuming that PHP developers and testers are new to BDD, we made the agenda ‘Behat from Scratch‘. There were about 15 behat users who attended this event.

As per the schedule, we had great Pizza before kick-off. While having drinks and Pizza, An Event organizer, Mitch asked everyone to introduced themselves and asked about their experience with Behat. All members were keen to know about other behat users and how long they have been using behat and BDD. After introductions, I explained a little bit about the ‘London Behat users’ group.

Live Coding (Developers View)

Jakub Zalas kicked it off with a talk about the developer’s view in BDD projects. He started the demonstration with a short introduction to BDD, how BDD is different from TDD and so on. Jakub covered following topics while coding:

1. Behat/Mink Installation

Jakub created composer.json file in the project root:

Then he downloaded composer.phar and ran install command which installed all the dependencies of Behat as well as Mink.

2. Creating first project

Once he was done with all the installations, he created a project called “Behat From Scratch” and initialized behat using:

$ behat --init
+d features - place your *.feature files here
+d features/bootstrap - place bootstrap scripts and static files here
+f features/bootstrap/FeatureContext.php - place your feature related code here 

The theme of the application was very simple. There was a form with two fields called ‘Title” and ‘Body” and a button called “Preview.” When a user fills in data in the ‘Title’ & ‘Body” fields and clicked on the “Preview” button, then the user should see the text that they entered.

3. Writing first Gherkin feature

Next he wrote one Gherkin feature file with couple of scenarios:

Feature: Previewing article
As a Content Manager
I want to preview an article before saving it
In order to make sure it is displayed correctly

Scenario: Article is displayed in a preview area
Given I visit "article form"
And I fill in "Hello Behat!" for "Title"
And I fill in "BDD is fun" for "Body"
When I press "Preview"
Then I should see "Hello Behat!" in the preview area
And I should see "BDD is fun" in the preview area

Scenario: Preview is not visible initially
Given I visit "article form"
Then the preview area should not be visible 

After that, he implemented Step Definitions for the integrated classes based on the Silex micro-framework, uses Twig templates and Symfony‘s form component. He implemented all the step definitions until all the steps passed.

The Source code of this is available on GitHub: Behat From Scratch

Browser Automation with Mink (Testers View)

Once Jakub finished with implementation, he handed it over to me to explain how to do browser automation using Mink. I modified the ‘config/behat.yml’ file and tagged the scenarios with ‘@javascript’ tags.

I also explained how to run feature files using different Mink drivers. Behat has provided lot of driver options for testers. It is not limited to Selenium. It has following mink drivers.

Selenium Server

You need to download the selenium server jar file and execute the following command:

$ cd /path/to/selenium-server
$java -jar selenium-server-standalone-2.15.0.jar 

Sahi Server

Download the sahi zip file from SourceForge

Now launch Sahi Server using the command below:

$ cd /path/to/sahi
$ cd userdata/bin
$bash start_sahi.sh 

There was a quick demonstration of the tests running in browsers using the Selenium 1, 2 (WebDriver), and Sahi servers. This was followed by a short question and answer session.

Try this on your own

You may be interested in trying all this stuff on your own. Jakub mentioned all of the instructions in his GitHub project. I will briefly explain the steps to follow:

$ moonstar:~ sjagtap$ git clone git://github.com/jakzal/behat-from-scratch.git
      Cloning into behat-from-scratch...
      remote: Counting objects: 123, done.
      remote: Compressing objects: 100% (59/59), done.
      remote: Total 123 (delta 47), reused 123 (delta 47)
      Receiving objects: 100% (123/123), 63.34 KiB, done.
      Resolving deltas: 100% (47/47), done.
      moonstar:~ sjagtap$ cd behat-from-scratch/ 
  • Install Behat with Composer
    Download the Composer and install Behat:
$ moonstar:behat-from-scratch sjagtap$ wget  http://getcomposer.org/composer.phar
% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
Dload  Upload   Total   Spent    Left  Speed
       100  308k  100  308k    0     0   366k      0 --:--:-- --:--:-- --:--:--  582k

$moonstar:behat-from-scratch sjagtap$ php composer.phar install 

Here, you may face some problems while installing, depending on your network and permission issues. (There may be a bug in composer.)

I managed to install it properly and it’s up and running in my localhost. You need to cross your fingers at this point.
By default the custom  Silex micro-framework session is used so there’s no need for additional configuration. Behat will create a Silex application and simulate requests.

All the project’s scenarios can be run with:

$ moonstar:behat-from-scratch sjagtap./bin/behat
  As a Content Manager
I want to preview an article before saving it
In order to make sure it is displayed correctly

Scenario: Article form is accessible from the homepage # features/previewing-article.feature:7
Given I visit "homepage"                             # FeatureContext::iVisit()
When I follow "Add article"                          # FeatureContext::clickLink()
Then I should see "Title" input on the article form  # FeatureContext::iShouldSeeInputOnTheArticleForm()
And I should see "Body" textarea on the article form # FeatureContext::iShouldSeeTextareaOnTheArticleForm()

Scenario: Article is displayed in a preview area       # features/previewing-article.feature:14
Given I visit "article form"                         # FeatureContext::iVisit()
And I fill in "Hello Behat!" for "Title"             # FeatureContext::fillField()
And I fill in "BDD is fun" for "Body"                # FeatureContext::fillField()
When I press "Preview"                               # FeatureContext::pressButton()
Then I should see "Hello Behat!" in the preview area # FeatureContext::iShouldSeeInPreviewArea()
And I should see "BDD is fun" in the preview area    # FeatureContext::iShouldSeeInPreviewArea()

Scenario: Preview is not visible initially             # features/previewing-article.feature:23
Given I visit "article form"                         # FeatureContext::iVisit()
Then the preview area should not be visible          # FeatureContext::thePreviewAreaShouldNotBeVisible()

Scenario: Title and body are required                  # features/previewing-article.feature:28
Given I visit "article form"                         # FeatureContext::iVisit()
When I press "Preview"                               # FeatureContext::pressButton()
Then I should see "Article title is required"        # FeatureContext::assertPageContainsText()
And I should see "Article body is required"          # FeatureContext::assertPageContainsText()
And the preview area should not be visible           # FeatureContext::thePreviewAreaShouldNotBeVisible()

4 scenarios (4 passed)
17 steps (17 passed)
0m12.957s 

You don’t need to configure the web server to run scenarios using Silex driver.  But you do need to configure the web server while running tests in browser.

Configure Web Server.

Follow these steps to configure the web server.

  1. Update ‘hosts’ file and add ‘behat.dev’ and IP as follows
$moonstar:~ sjagtap$ cd /etc
$moonstar:etc sjagtap$ sudo vi hosts
# Host Database
     # localhost is used to configure the loopback interface
     # when the system is booting.  Do not change this entry.
      ##
    127.0.0.1       localhost
    127.0.0.1  behat.dev 
  • Make sure you have updated ‘/etc/apache2/httpd.conf’ to enable virtual host. Remove the comment from Virtual hosts.
$moonstar:~ sjagtap$ cd /etc/apache2/
$moonstar:apache2 sjagtap$ cat httpd.conf
 # Virtual hosts
     Include /private/etc/apache2/extra/httpd-vhosts.conf 
  • Now you need to update the ‘/etc/apache2/extra/httpd-vhosts.conf ‘ file and add the following configuration to it:
$mmoonstar:~ sjagtap$ cd /etc/apache2/extra/
$moonstar:extra sjagtap$ sudo vi httpd-vhosts.conf
     VirtualHost *:80;
ServerName behat.dev

DocumentRoot /var/www/behat.dev/web
DirectoryIndex index.php

Directory /var/www/behat.dev/web&gt;
Options FollowSymLinks
AllowOverride All
Order allow,deny
allow from all
/Directory&gt;
     /VirtualHost&gt;

You are done with web server configuration, and now you can run your tests through a browser.  The Paths to source code and a domain name will have to be updated. Also the base_url in  ‘config/behat.yml’ needs to be changed accordingly.

Run Tests in Browser

  • Tag all your scenarios with ‘@javascript’ tags
  • Run Selenium server as mentioned above
$ cd /path/to/selenium-server
$java -jar selenium-server-standalone-2.15.0.jar
  • Update ‘config/behat.yml’
default:
context:
parameters:
default_session: goutte
javascript_session: webdriver
browser: firefox
               base_url: http://behat.dev/
  • Run ‘./bin/behat’ from a terminal and watch results in browser.
$ moonstar:behat-from-scratch sjagtap./bin/behat
Feature: Previewing article
As a Content Manager
I want to preview an article before saving it
In order to make sure it is displayed correctly

@javascript
Scenario: Article form is accessible from the homepage # features/previewing-article.feature:7
Given I visit "homepage"                             # FeatureContext::iVisit()
When I follow "Add article"                          # FeatureContext::clickLink()
Then I should see "Title" input on the article form  # FeatureContext::iShouldSeeInputOnTheArticleForm()
And I should see "Body" textarea on the article form # FeatureContext::iShouldSeeTextareaOnTheArticleForm()

@javascript
Scenario: Article is displayed in a preview area       # features/previewing-article.feature:14
Given I visit "article form"                         # FeatureContext::iVisit()
And I fill in "Hello Behat!" for "Title"             # FeatureContext::fillField()
And I fill in "BDD is fun" for "Body"                # FeatureContext::fillField()
When I press "Preview"                               # FeatureContext::pressButton()
Then I should see "Hello Behat!" in the preview area # FeatureContext::iShouldSeeInPreviewArea()
And I should see "BDD is fun" in the preview area    # FeatureContext::iShouldSeeInPreviewArea()

@javascript
Scenario: Preview is not visible initially             # features/previewing-article.feature:23
Given I visit "article form"                         # FeatureContext::iVisit()
Then the preview area should not be visible          # FeatureContext::thePreviewAreaShouldNotBeVisible()

@javascript
Scenario: Title and body are required                  # features/previewing-article.feature:28
Given I visit "article form"                         # FeatureContext::iVisit()
When I press "Preview"                               # FeatureContext::pressButton()
Then I should see "Article title is required"        # FeatureContext::assertPageContainsText()
And I should see "Article body is required"          # FeatureContext::assertPageContainsText()
And the preview area should not be visible           # FeatureContext::thePreviewAreaShouldNotBeVisible()

4 scenarios (4 passed)
17 steps (17 passed)
0m12.957s

It’s done !!

Discussion about Behat and BDD

After we finished with the demo, we started a discussion about BDD and behat. To me, this was the most interesting part of the meetup. Lot of things about BDD, tester-developer collaboration, acceptance criteria, Jenkins and other CI systems were discussed.

Some of the highlights of the discussion are as follows:

  • Ben and Jakub Zalas  shared thoughts about test reporting with Jenkins. (using HTML reports).
  • Mitch raised points about making scenarios and running scenarios with different data sets and everybody contributed
  • Marcello talked about the role of testers and developers in BDD
  • Miles and Alex raised some good questions about web testing using Gherkin DSL.
  • John played a key role within the whole session talking about collaborative tools, challenges in BDD and some tricks about BDD.

Conclusion:

The first Behat meetup was an amazing experience for all the attendees. Everybody learned by sharing experiences and ideas. In short, all of us enjoyed our evening of knowledge sharing. We are looking forward to arrange monthly meetups to further discuss Behat and BDD.  The next meetup is tentatively scheduled for Wed Mar 21 at 7:00 PM (GMT). Click here for details.

Many Thanks to the creator of Behat: ‘Konstantin Kudryashov

 

Happy BDD !!

Web Acceptance Testing Framework for PHP

9 Jan

Web Acceptance Testing Framework for PHP

A Web acceptance testing  framework for PHP is now available on GitHub. It can be used for web acceptance testing of the PHP projects. This framework is build around Behat, Mink, Sauce Labs and ANT. You can configure it with a continuous integration server like Jenkins.

Behat is a BDD framework for PHP.  Behat comes up with Mink  which is used for browser emulation (functional testing) where browser interaction takes place. Behat and Mink combination is used for web acceptance testing.

 Key features of web acceptance testing framework

  • Selenium and Sahi servers are plugged into build file, user doesn’t need to download or launch Selenium or Sahi server while running features with ANT or Jenkins.
  • Test reports are generated in HTML and xml format in “/report” directory.
  • Easy switching over to another driver. You can run tests using any available drivers, just by specifying name of them.
  • Framework is integrated with cloud testing service called “Sauce Labs”. You can run your features in cloud with selenium driver.
  • Testers can get started easily without any hassles.
  • With little changes in config file, it is ready for your project.

Behat for Testers

Testers might have tried Cucumber & Selenium or Cucumber & capybara combination for Ruby projects. BDD for testers could be very interesting topic to discuss. Testers can now use BDD framework for PHP project as well. Thanks to Behat !

Behat has provided lot of driver options for testers. Its not limited to selenium. It has following mink drivers.

Tester can pick one of these and start implementing features. Goutte can be used for tests which doesn’t need browser interaction. Tester can always switch to another driver if feature is failing for one of the driver. There are some pro’s and con’s of each driver


Sahi Selenium Webdriver




Implicit Wait Yes No Yes
Hidden Link Access Yes Yes No
Sauce Lab Support No Yes No
Speed Medium Medium Fast
Https sites testing Hectic, need to add certificate exception Accepts certificated automatically Accepts certificated automatically

It is very important to choose right driver for your testing. It depends on your application and requirement. This framework makes it easy to switch over to another driver.

What you need to use framework?

Install Behat using Behat documentation which explained all these methods in simple way. Similarly install mink using Mink documentation.

  • Create Your Project

Initiate Behat:

$ behat --init
  • Clone Web Acceptance testing  Framework from GitHub

  1. Clone test framework from Github into your local machine.
  2. Make sure you have initialized Behat in your root directory, currently its “Behat”.
  3. Now you are ready to use the framework for adding features and running them with different drivers like Selenium, Sahi or webdriver.
  • How to use framework?
  1. Change “base_url” “browser” parameter in all config files like ‘behat.yml’, ‘sahi.yml’, ‘selenium.yml’, and ‘webdriver.yml’ as per your project requirement. eg change in sahi.yml file as shown below
default:
context:
parameters:
javascript_session: sahi
base_url: http://{your url}
browser: {your browser}
show_cmd: open %s 

Run features locally

To run feature locally, you need to start Selenium or Sahi server before executing them.

Download Selenium or Sahi and launch Selenium or Sahi server as shown below

Selenium Server

You need to download selenium server jar file and execute following command:

$ cd /path/to/selenium-server
$java -jar selenium-server-standalone-2.15.0.jar 

Sahi Server

Download sahi zip file from SourceForge

Now launch Sahi Server using command below:

$ cd /path/to/sahi
$ cd userdata/bin
$bash start_sahi.sh

Now you can run behat command to run feature locally

$ cd /path/to/behat
$behat --name wikiSearch (your feature)

You can see feature running on your local host.

  • How to run features using ANT

Requirement
You need to install Apache Ant on your localhost. You can download and install Ant from Apache Ant website.

No need install or download selenium or Sahi. It is configured inside this framework. Ant will automatically launch selenium or Sahi server still you need to update version of selenium server frequently.

Now you got three drivers options to run your features

  1. Sahi Driver
  2. Selenium Driver
  3. Selenium 2 Driver (webdriver)
  • Run feature with selenium driver
$ cd /path/to/my/project
$ant runSelenium 
  • Run feature with Sahi driver.
$ cd /path/to/my/project
$ant runSahi 
  • Run feature with webdriver
$ cd /path/to/my/project
$ant runWebdriver
$ cd /path/to/my/project
$ant sauceTests 

If you are using selenium driver, then you have to implement wait in your step definitions every time there is new page is loaded like this:

$this->getMink()->getSession()->wait("3000");

Sahi driver waits automatically for element to be appear on page or page to load. You don’t have to implement wait if you would like to use Sahi driver.

Once you run ‘ant’ command from terminal you will see your feature running in browser, you configured.You will see reports generated in “/report” directory. There will be HTML reports as well.

Configure Jenkins to run features

 

  • Download & Launch Jenkins by executing below command:
$  java -jar jenkins.war

Visit url : http://localhost:8080 to access Jenkins in browser. You can specify different port to launch Jenkins.

  • Create new Build a free-style software project and name it “Behat”
  • Configure job by specifying your repository.(Git, SVN, CSV)
  • You need to Invoke Ant as shown below

Jenkins Configuration

If you wish to run tests using Sahi driver then specify target as “runSahi”

You can see reports generated once you run your feature.

Conclusion

Using web acceptance test framework for PHP, you can write features and run them easily on ANT, Jenkins and Sauce labs with choice of available drivers.

Happy BDD for testers !! Any questions or comment mention me @Shashikant86 on Twitter.