第13章 PHPUnit と Selenium

Selenium Server

Selenium Server はテストツールのひとつです。これは、OS を通してブラウザのプロセスを動かし、 ブラウザのタスクを自動実行します。 あらゆるプログラミング言語で稼動しているウェブサイトに対応しており、 現在主流のあらゆるブラウザで使用することができます。Selenium RC は Selenium Core を使用しています。これは、ブラウザ上でのタスクを自動的に実行する JavaScript のライブラリです。Selenium でのテストは、 一般のユーザが使用するのと同じようにブラウザ上で直接実行されます。 主な使用例としては、受け入れテスト (各システム単体のテストではなく、結合されたシステム全体に対するテスト) や ブラウザの互換性のテスト (ウェブアプリケーションを、さまざまなオペレーティングシステムやブラウザでテストする) などがあります。

PHPUnit_Selenium がサポートしている唯一のシナリオは、 Selenium 2.x サーバを使うものです。 Selenium 2.x サーバにアクセスするには、1.0 から存在する古い形式の Selenium RC API を使うか、 あるいは PHPUnit_Selenium 1.2 で一部実装済みの WebDriver API を使います。

なぜそうしたかというと、Selenium 2 には後方互換性があり、 Selenium RC がもうメンテナンスされていないからです。

インストール

まず、Selenium Server をインストールします。

  1. Selenium Server の配布アーカイブをダウンロードする。
  2. アーカイブを展開し、selenium-server-standalone-2.9.0.jar (バージョンをチェックすること) を /usr/local/bin などにコピーする。
  3. java -jar /usr/local/bin/selenium-server-standalone-2.9.0.jar などのようにして Selenium RC サーバを起動する。

PHPUnit_Selenium パッケージは、PHPUnit の PHAR 版の中に含まれています。 Composer でインストールするには、 "require-dev" に次の行を追加します。

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

これで、クライアント/サーバ プロトコルを用いて Selenium Server にコマンドを送信できるようになりました。

PHPUnit_Extensions_Selenium2TestCase

PHPUnit_Extensions_Selenium2TestCase テストケースは、 WebDriver API を利用します (実装しているのはその一部だけです)。

例 13.1 は、 ウェブサイト http://www.example.com/<title> 要素の内容をテストする方法を示したものです。

例 13.1: 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.


Selenium2TestCare のコマンドは __call() を使って実装しています。 サポートする機能の一覧は PHPUnit_Extensions_Selenium2TestCase のエンドツーエンドテスト を参照ください。

PHPUnit_Extensions_SeleniumTestCase

PHPUnit_Extensions_SeleniumTestCase は、Selenium Server と通信するための クライアント/サーバ プロトコルを実装したものです。 また、ウェブのテスト用に特化したアサーションメソッドも提供します。

例 13.2 は、 ウェブサイト http://www.example.com/<title> 要素の内容をテストする方法を示したものです。

例 13.2: 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.


PHPUnit_Framework_TestCase クラスとは異なり、 PHPUnit_Extensions_SeleniumTestCase を継承したテストケースクラスは setUp() メソッドが必須となります。 このメソッド内で、Selenium Server セッションの設定を行います。 ここで使用できるメソッドの一覧は 表 13.1 を参照ください。

表13.1 Selenium Server API: セットアップ

メソッド意味
void setBrowser(string $browser)Selenium Server が使用するブラウザを設定します。
void setBrowserUrl(string $browserUrl)テストするベース URL を設定します。
void setHost(string $host)Selenium Server に接続する際のホスト名を設定します。
void setPort(int $port)Selenium Server に接続する際のポートを設定します。
void setTimeout(int $timeout)Selenium Server に接続する際のタイムアウト値を設定します。
void setSleep(int $seconds)Selenium Server クライアントが、Selenium Server のサーバにアクションコマンドを送信してから待機する秒数を設定します。


PHPUnit では、Selenium のテストが失敗したときのスクリーンショットを撮ることができます。 この機能を使うには、$captureScreenshotOnFailure$screenshotPath および $screenshotUrl をテストケースクラス内で 例 13.3 のように指定します。

例 13.3: テストに失敗したときのスクリーンショットの取得

<?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.


複数のブラウザを使用してテストを行なうこともできます。この場合は、 setBrowser() でブラウザの設定を行うかわりに、 テストケースクラスの中で $browsers という名前の public static な配列を作成します。 この配列の各項目が個々のブラウザの設定を表します。 これらのブラウザは、それぞれ別の Selenium Server のサーバで管理することができます。 例 13.4 に例を示します。

例 13.4: 複数のブラウザの設定管理

<?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 を使用すると、 Selenium で実行したテストのカバレッジ情報を収集することができます。

  1. PHPUnit/Extensions/SeleniumCommon/phpunit_coverage.php をウェブサーバのドキュメントルートディレクトリにコピーします。
  2. ウェブサーバ上の php.ini ファイルで、PHPUnit/Extensions/SeleniumCommon/prepend.phpPHPUnit/Extensions/SeleniumCommon/append.php をそれぞれ auto_prepend_file および auto_append_file に設定します。
  3. PHPUnit_Extensions_SeleniumTestCase を継承したテストケースクラスで、
    protected $coverageScriptUrl = 'http://host/phpunit_coverage.php';
    のようにして phpunit_coverage.php スクリプトの URL を指定します。

表 13.2 は、PHPUnit_Extensions_SeleniumTestCase が提供するさまざまなアサーションメソッドの一覧です。

表13.2 アサーション

アサーション意味
void assertElementValueEquals(string $locator, string $text)$locator で表される要素の値が $text と異なる場合にエラーを報告します。
void assertElementValueNotEquals(string $locator, string $text)$locator で表される要素の値が $text と等しい場合にエラーを報告します。
void assertElementValueContains(string $locator, string $text)$locator で表される要素の値が $text を含まない場合にエラーを報告します。
void assertElementValueNotContains(string $locator, string $text)$locator で表される要素の値が $text を含む場合にエラーを報告します。
void assertElementContainsText(string $locator, string $text)$locator で表される要素が $text を含まない場合にエラーを報告します。
void assertElementNotContainsText(string $locator, string $text)$locator で表される要素が $text を含む場合にエラーを報告します。
void assertSelectHasOption(string $selectLocator, string $option)指定したオプションが使用できない場合にエラーを報告します。
void assertSelectNotHasOption(string $selectLocator, string $option)指定したオプションが使用できる場合にエラーを報告します。
void assertSelected($selectLocator, $option)指定したラベルが選択されていない場合にエラーを報告します。
void assertNotSelected($selectLocator, $option)指定したラベルが選択されている場合にエラーを報告します。
void assertIsSelected(string $selectLocator, string $value)指定した値が選択されていない場合にエラーを報告します。
void assertIsNotSelected(string $selectLocator, string $value)指定した値が選択されている場合にエラーを報告します。


表 13.3 は、 PHPUnit_Extensions_SeleniumTestCase のテンプレートメソッドをまとめたものです。

表13.3 テンプレートメソッド

メソッド意味
void defaultAssertions() テストケース内のすべてのテストで共有するアサーションを上書きします。 このメソッドは、Selenium Server のサーバにコマンドが送信されるたびに (送信された後に) コールされます。


使用できるコマンドのリファレンスや実際の使用法については Selenium のドキュメント を参照ください。

Selenium 1 のコマンドは、__call で動的に実装されています。 PHPUnit_Extensions_SeleniumTestCase_Driver::__call() の API ドキュメント に、PHP 側で対応しているすべてのメソッドの一覧があります。 また、引数や返り値の型も確認できます。

runSelenese($filename) メソッドを使用すると、 Selenese/HTML の設定から Selenium のテストを実行することができます。 さらに、静的属性 $seleneseDirectory を使用すると、 Selenese/HTML ファイルを含むディレクトリから自動的にテストオブジェクトを作成することができます。 指定したディレクトリ配下を再帰的に走査し、 .htm ファイルを探します。このファイルには Selenese/HTML が含まれているものとします。例として 例 13.5 を参照ください。

例 13.5: Selenese/HTML ファイルのディレクトリをテストとして使用する

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

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


Selenium 1.1.1 から取り込まれた実験的な機能として、ユーザーが複数のテストでセッションを共有できるようになりました。 現在サポートしているのは、ひとつのブラウザを使うときに全テストでセッションを共有するという場合だけです。 セッションの共有機能を使うには、ブートストラップファイルで PHPUnit_Extensions_SeleniumTestCase::shareSession(true) をコールします。 テストが成功しなかった (失敗、あるいは不完全) 場合は、共有セッションがリセットされます。 クッキーをリセットしたり、(tearDown() メソッドで) テスト対象のアプリケーションからログアウトしたりして テストがお互い干渉しあわないようにするのは、ユーザ側の責任となります。