Prev Next

第17章 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 から Selenium Server へネイティブにアクセスするために必要です。

pear install phpunit/PHPUnit_Selenium

を実行しましょう。

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

PHPUnit_Extensions_Selenium2TestCase

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

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

例 17.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 3.6.10 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 と通信するための クライアント/サーバ プロトコルを実装したものです。 また、ウェブのテスト用に特化したアサーションメソッドも提供します。

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

例 17.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 3.6.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 セッションの設定を行います。 ここで使用できるメソッドの一覧は 表 17.1 を参照ください。

表17.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 をテストケースクラス内で 例 17.3 のように指定します。

例 17.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 3.6.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 のサーバで管理することができます。 例 17.4 に例を示します。

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

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

表17.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) 指定した値が選択されている場合にエラーを報告します。

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

表17.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 が含まれているものとします。例として 例 17.5 を参照ください。

例 17.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() メソッドで) テスト対象のアプリケーションからログアウトしたりして テストがお互い干渉しあわないようにするのは、ユーザ側の責任となります。

Prev Next
1. 自動テスト
2. PHPUnit の目標
3. PHPUnit のインストール
4. PHPUnit 用のテストの書き方
テストの依存性
データプロバイダ
例外のテスト
PHP のエラーのテスト
出力内容のテスト
アサーション
assertArrayHasKey()
assertClassHasAttribute()
assertClassHasStaticAttribute()
assertContains()
assertContainsOnly()
assertCount()
assertEmpty()
assertEqualXMLStructure()
assertEquals()
assertFalse()
assertFileEquals()
assertFileExists()
assertGreaterThan()
assertGreaterThanOrEqual()
assertInstanceOf()
assertInternalType()
assertLessThan()
assertLessThanOrEqual()
assertNull()
assertObjectHasAttribute()
assertRegExp()
assertStringMatchesFormat()
assertStringMatchesFormatFile()
assertSame()
assertSelectCount()
assertSelectEquals()
assertSelectRegExp()
assertStringEndsWith()
assertStringEqualsFile()
assertStringStartsWith()
assertTag()
assertThat()
assertTrue()
assertXmlFileEqualsXmlFile()
assertXmlStringEqualsXmlFile()
assertXmlStringEqualsXmlString()
5. コマンドラインのテストランナー
Command-Line switches
6. Fixtures
tearDown() よりも setUp()
バリエーション
Fixture の共有
グローバルな状態
7. テストの構成
ファイルシステムを用いたテストスイートの構成
XML 設定ファイルを用いたテストスイートの構成
8. データベースのテスト
データベースのテストに対応しているベンダー
データベースのテストの難しさ
データベーステストの四段階
1. データベースのクリーンアップ
2. フィクスチャの準備
3–5. テストの実行、結果の検証、そして後始末
PHPUnit のデータベーステストケースの設定
getConnection() の実装
getDataSet() の実装
データベーススキーマ (DDL) とは?
ヒント: 自前でのデータベーステストケースの抽象化
データセットとデータテーブルについて知る
利用できる実装
外部キーには注意
自作のデータセットやデータテーブルの実装
接続 API
データベースアサーション API
テーブルの行数のアサーション
テーブルの状態のアサーション
クエリの結果のアサーション
複数のテーブルの状態のアサーション
よくある質問
PHPUnit は、テストごとにデータベーススキーマを作り直すの?
PDO を使ったアプリケーションじゃないと Database Extension を使えないの?
Too much Connections というエラーが出たらどうすればいい?
フラット XML や CSV のデータセットで NULL を扱う方法は?
9. 不完全なテスト・テストの省略
不完全なテスト
テストの省略
10. テストダブル
スタブ
モックオブジェクト
ウェブサービスのスタブおよびモック
ファイルシステムのモック
11. テストの進め方
開発中のテスト
デバッグ中のテスト
12. テスト駆動開発
銀行口座の例
13. 振舞駆動開発
ボウリングゲームの例
14. コードカバレッジ解析
カバーするメソッドの指定
コードブロックの無視
ファイルのインクルードや除外
エッジケース
15. テストのその他の使用法
アジャイルな文書作成
複数チームでのテスト
16. 雛形ジェネレータ
テストケースクラスの雛形の作成
テストケースクラスからのクラスの雛形の作成
17. PHPUnit と Selenium
Selenium Server
インストール
PHPUnit_Extensions_Selenium2TestCase
PHPUnit_Extensions_SeleniumTestCase
18. ログ出力
テスト結果 (XML)
テスト結果 (TAP)
テスト結果 (JSON)
コードカバレッジ (XML)
コードカバレッジ (テキスト)
19. PHPUnit の拡張
PHPUnit_Framework_TestCase のサブクラスの作成
カスタムアサーションの作成
PHPUnit_Framework_TestListener の実装
PHPUnit_Extensions_TestDecorator のサブクラスの作成
PHPUnit_Framework_Test の実装
A. アサーション
B. アノテーション
@assert
@author
@backupGlobals
@backupStaticAttributes
@codeCoverageIgnore*
@covers
@dataProvider
@depends
@expectedException
@expectedExceptionCode
@expectedExceptionMessage
@group
@outputBuffering
@runTestsInSeparateProcesses
@runInSeparateProcess
@test
@testdox
@ticket
C. XML 設定ファイル
PHPUnit
テストスイート
グループ
コードカバレッジ対象のファイルの追加や除外
ログ出力
テストリスナー
PHP INI 項目や定数、グローバル変数の設定
Selenium RC の設定ブラウザ
D. 目次
E. 参考文献
F. 著作権