Chapter 13. PHPUnit and Selenium

Selenium Server

Selenium Server is a test tool that allows you to write automated user-interface tests for web applications in any programming language against any HTTP website using any mainstream browser. It performs automated browser tasks by driving the browser's process through the operating system. Selenium tests run directly in a browser, just as real users do. These tests can be used for both acceptance testing (by performing higher-level tests on the integrated system instead of just testing each unit of the system independently) and browser compatibility testing (by testing the web application on different operating systems and browsers).

The only supported scenario of PHPUnit_Selenium is that of a Selenium 2.x server. The server can be accessed through the classic Selenium RC Api, already present in 1.x, or with the WebDriver API (partially implemented) from PHPUnit_Selenium 1.2.

The reason behind this decision is that Selenium 2 is backward compatible and Selenium RC is not maintained anymore.

Installation

First, install the Selenium Server:

  1. Download a distribution archive of Selenium Server.
  2. Unzip the distribution archive and copy selenium-server-standalone-2.9.0.jar (check the version suffix) to /usr/local/bin, for instance.
  3. Start the Selenium Server server by running java -jar /usr/local/bin/selenium-server-standalone-2.9.0.jar.

The PHPUnit_Selenium package is included in the PHAR distribution of PHPUnit. It can be installed via Composer by adding the following "require-dev" dependency:

"phpunit/phpunit-selenium": ">=1.2"

Now we can send commands to the Selenium Server using its client/server protocol.

PHPUnit_Extensions_Selenium2TestCase

The PHPUnit_Extensions_Selenium2TestCase test case lets you use the WebDriver API (partially implemented).

Example 13.1 shows how to test the contents of the <title> element of the http://www.example.com/ website.

Example 13.1: Usage example for PHPUnit_Extensions_Selenium2TestCase

<?php
class WebTest extends PHPUnit_Extensions_Selenium2TestCase
{
    protected function setUp()
    {
        $this->setBrowser('firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->url('http://www.example.com/');
        $this->assertEquals('Example WWW Page', $this->title());
    }

}
?>
phpunit WebTest
PHPUnit 4.2.0 by Sebastian Bergmann.

F

Time: 28 seconds, Memory: 3.00Mb

There was 1 failure:

1) WebTest::testTitle
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'Example WWW Page'
+'IANA — Example domains'

/home/giorgio/WebTest.php:13

FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


The commands of Selenium2TestCare are implemented via __call(). Please refer to the end-to-end test for PHPUnit_Extensions_Selenium2TestCase for a list of every supported feature.

PHPUnit_Extensions_SeleniumTestCase

The PHPUnit_Extensions_SeleniumTestCase test case extension implements the client/server protocol to talk to Selenium Server as well as specialized assertion methods for web testing.

Example 13.2 shows how to test the contents of the <title> element of the http://www.example.com/ website.

Example 13.2: Usage example for PHPUnit_Extensions_SeleniumTestCase

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    protected function setUp()
    {
        $this->setBrowser('*firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example WWW Page');
    }
}
?>
phpunit WebTest
PHPUnit 4.2.0 by Sebastian Bergmann.

F

Time: 9 seconds, Memory: 6.00Mb

There was 1 failure:

1) WebTest::testTitle
Current URL: http://www.iana.org/domains/example/

Failed asserting that 'IANA — Example domains' matches PCRE pattern "/Example WWW Page/".


FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


Unlike with the PHPUnit_Framework_TestCase class, test case classes that extend PHPUnit_Extensions_SeleniumTestCase have to provide a setUp() method. This method is used to configure the Selenium Server session. See Table 13.1 for the list of methods that are available for this.

Table 13.1. Selenium Server API: Setup

MethodMeaning
void setBrowser(string $browser)Set the browser to be used by the Selenium Server server.
void setBrowserUrl(string $browserUrl)Set the base URL for the tests.
void setHost(string $host)Set the hostname for the connection to the Selenium Server server.
void setPort(int $port)Set the port for the connection to the Selenium Server server.
void setTimeout(int $timeout)Set the timeout for the connection to the Selenium Server server.
void setSleep(int $seconds)Set the number of seconds the Selenium Server client should sleep between sending action commands to the Selenium Server server.


PHPUnit can optionally capture a screenshot when a Selenium test fails. To enable this, set $captureScreenshotOnFailure, $screenshotPath, and $screenshotUrl in your test case class as shown in Example 13.3.

Example 13.3: Capturing a screenshot when a test fails

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    protected $captureScreenshotOnFailure = TRUE;
    protected $screenshotPath = '/var/www/localhost/htdocs/screenshots';
    protected $screenshotUrl = 'http://localhost/screenshots';

    protected function setUp()
    {
        $this->setBrowser('*firefox');
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example WWW Page');
    }
}
?>
phpunit WebTest
PHPUnit 4.2.0 by Sebastian Bergmann.

F

Time: 7 seconds, Memory: 6.00Mb

There was 1 failure:

1) WebTest::testTitle
Current URL: http://www.iana.org/domains/example/
Screenshot: http://localhost/screenshots/334b080f2364b5f11568ee1c7f6742c9.png

Failed asserting that 'IANA — Example domains' matches PCRE pattern "/Example WWW Page/".


FAILURES!
Tests: 1, Assertions: 1, Failures: 1.


You can run each test using a set of browsers: Instead of using setBrowser() to set up one browser you declare a public static array named $browsers in your test case class. Each item in this array describes one browser configuration. Each of these browsers can be hosted by different Selenium Server servers. Example 13.4 shows an example.

Example 13.4: Setting up multiple browser configurations

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class WebTest extends PHPUnit_Extensions_SeleniumTestCase
{
    public static $browsers = array(
      array(
        'name'    => 'Firefox on Linux',
        'browser' => '*firefox',
        'host'    => 'my.linux.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Safari on MacOS X',
        'browser' => '*safari',
        'host'    => 'my.macosx.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Safari on Windows XP',
        'browser' => '*custom C:\Program Files\Safari\Safari.exe -url',
        'host'    => 'my.windowsxp.box',
        'port'    => 4444,
        'timeout' => 30000,
      ),
      array(
        'name'    => 'Internet Explorer on Windows XP',
        'browser' => '*iexplore',
        'host'    => 'my.windowsxp.box',
        'port'    => 4444,
        'timeout' => 30000,
      )
    );

    protected function setUp()
    {
        $this->setBrowserUrl('http://www.example.com/');
    }

    public function testTitle()
    {
        $this->open('http://www.example.com/');
        $this->assertTitle('Example Web Page');
    }
}
?>


PHPUnit_Extensions_SeleniumTestCase can collect code coverage information for tests run through Selenium:

  1. Copy PHPUnit/Extensions/SeleniumCommon/phpunit_coverage.php into your webserver's document root directory.
  2. In your webserver's php.ini configuration file, configure PHPUnit/Extensions/SeleniumCommon/prepend.php and PHPUnit/Extensions/SeleniumCommon/append.php as the auto_prepend_file and auto_append_file, respectively.
  3. In your test case class that extends PHPUnit_Extensions_SeleniumTestCase, use
    protected $coverageScriptUrl = 'http://host/phpunit_coverage.php';
    to configure the URL for the phpunit_coverage.php script.

Table 13.2 lists the various assertion methods that PHPUnit_Extensions_SeleniumTestCase provides.

Table 13.2. Assertions

AssertionMeaning
void assertElementValueEquals(string $locator, string $text)Reports an error if the value of the element identified by $locator is not equal to the given $text.
void assertElementValueNotEquals(string $locator, string $text)Reports an error if the value of the element identified by $locator is equal to the given $text.
void assertElementValueContains(string $locator, string $text)Reports an error if the value of the element identified by $locator does not contain the given $text.
void assertElementValueNotContains(string $locator, string $text)Reports an error if the value of the element identified by $locator contains the given $text.
void assertElementContainsText(string $locator, string $text)Reports an error if the element identified by $locator does not contain the given $text.
void assertElementNotContainsText(string $locator, string $text)Reports an error if the element identified by $locator contains the given $text.
void assertSelectHasOption(string $selectLocator, string $option)Reports an error if the given option is not available.
void assertSelectNotHasOption(string $selectLocator, string $option)Reports an error if the given option is available.
void assertSelected($selectLocator, $option)Reports an error if the given label is not selected.
void assertNotSelected($selectLocator, $option)Reports an error if the given label is selected.
void assertIsSelected(string $selectLocator, string $value)Reports an error if the given value is not selected.
void assertIsNotSelected(string $selectLocator, string $value)Reports an error if the given value is selected.


Table 13.3 shows the template method of PHPUnit_Extensions_SeleniumTestCase:

Table 13.3. Template Methods

MethodMeaning
void defaultAssertions()Override to perform assertions that are shared by all tests of a test case. This method is called after each command that is sent to the Selenium Server server.


Please refer to the documentation of Selenium commands for a reference of the commands available and how they are used.

The commands of Selenium 1 are implemented dynamically via __call. Refer also to the API docs for PHPUnit_Extensions_SeleniumTestCase_Driver::__call() for a list of all the supported methods on the PHP side, along with arguments and return type where available.

Using the runSelenese($filename) method, you can also run a Selenium test from its Selenese/HTML specification. Furthermore, using the static attribute $seleneseDirectory, you can automatically create test objects from a directory that contains Selenese/HTML files. The specified directory is recursively searched for .htm files that are expected to contain Selenese/HTML. Example 13.5 shows an example.

Example 13.5: Use a directory of Selenese/HTML files as tests

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class SeleneseTests extends PHPUnit_Extensions_SeleniumTestCase
{
    public static $seleneseDirectory = '/path/to/files';
}
?>


From Selenium 1.1.1, an experimental feature is included allowing the user to share the session between tests. The only supported case is to share the session between all tests when a single browser is used. Call PHPUnit_Extensions_SeleniumTestCase::shareSession(true) in your bootstrap file to enable session sharing. The session will be reset in the case of not successul tests (failed or incomplete); it is up to the user to avoid interactions between tests by resetting cookies or logging out from the application under test (with a tearDown() method).