Doctrineはユニットテストを使用するプログラムでテストされます。Wikipediaでユニットテストの記事を読むことができます。
Doctrineに搭載されるテストを実施するにはライブラリフォルダだけでなくプロジェクト全体をチェックアウトする必要があります。
$ svn co http://svn.doctrine-project.org/branches/1.2 /path/to/co/doctrine
Doctrineのチェックアウトのディレクトリに移動します。
$ cd /path/to/co/doctrine
次のファイルとディレクトリが見えます。
CHANGELOG
COPYRIGHT
lib/
LICENSE
package.xml
tests/
tools/
vendor/
認識できるテストの失敗ケースが用意されるのはめったにありません。もしくはDoctrineには後のバージョンまでコミットできないバグ修正もしくは強化リクエスト用のテストケースが存在します。もしくは単に問題の修正コードが存在しないので失敗のままのテストもあります。Doctrineのそれぞれのバージョンでどれだけの数のテストの失敗ケースがあるのかメーリングリストもしくはIRCでたずねることができます。
コマンドラインでテストを実施するには、php-cliをインストールしなければなりません。
/path/to/co/doctrine/testsフォルダに移動してrun.phpスクリプトを実行します:
$ cd /path/to/co/doctrine/tests
$ php run.php
これによってすべてのユニットテストを実行しているときに進行バーが出力されます。テストが終了したとき何が成功し何が失敗したのか報告されます。
CLIには特定のテスト、テストのグループを実施するもしくはテストスィートの名前でテストをフィルタリングするためのオプションがありあす。これらのオプションを確認するために次のコマンドを実行してください。
$ php run.php -help
次のように個別のテストグループを実行できます:
$ php run.php --group data_dict
doctrine/tests/run.phpに移動すればブラウザでユニットテストを実施できます。オプションは変数_GETを通して設定できます。
例:
テストの結果が環境に大きく左右されることがあることにご注意ください。例えばphp.iniのapc.enable_cliディレクティブが0に設定されている場合追加テストが失敗することがあります。
テストスィートを書き始めるとき、TemplateTestCase.phpをコピーすることから始めます。サンプルのテストケースは次の通りです:
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
public function prepareTables()
{
$this->tables[] = "MyModel1";
$this->tables[] = "MyModel2";
parent::prepareTables();
}
public function prepareData()
{
$this->myModel = new MyModel1();
//$this->myModel->save();
}
public function testInit()
{
}
// This produces a failing test
public function testTest()
{
$this->assertTrue($this->myModel->exists());
$this->assertEqual(0, 1);
$this->assertIdentical(0, '0');
$this->assertNotEqual(1, 2);
$this->assertTrue((5 < 1));
$this->assertFalse((1 > 2));
}
}
class Model1 extends Doctrine_Record
{
}
class Model2 extends Doctrine_Record
{
}
モデルの定義はテストケースファイルに直接含まれるもしくはこれらは/path/to/co/doctrine/tests/modelsに設置可能です。そうすればこれらはオートロードされます。
テストを書く作業を終えたら必ずrun.phpに次のコードを追加してください。
$test->addTestCase(new Doctrine_Sample_TestCase());
run.phpを実行するとき新しい失敗ケースが報告されます。
Doctrineにおいてtracに報告される個別のチケット用のテストの失敗ケースをコミットするのが慣行になっています。/path/to/co/doctrine/tests/Ticket/フォルダで見つかるすべてのテストケースを読むことでこれらの手数とケースは自動的にrun.phpに追加されます。
CLIから新しいテストケースのチケットを作成できます:
$ php run.php --ticket 9999
チケット番号9999がまだ存在しない場合空白のテストケースクラスが/path/to/co/doctrine/tests/Ticket/9999TestCase.phpに生成されます。
class Doctrine_Ticket_9999_TestCase extends Doctrine_UnitTestCase
{
}
// ...
public function test1Equals1()
{
$this->assertEqual(1, 1);
}
// ...
// ...
public function test1DoesNotEqual2()
{
$this->assertNotEqual(1, 2);
}
// ...
ロジックがより厳密で2つの値の比較に===を使用すること以外assertIdentical()メソッドはassertEqual()と同じです。
// ...
public function testAssertIdentical()
{
$this->assertIdentical(1, '1');
}
// ...
1番目の引数の数字の1がPHPの整数型としてキャストされるのに対して2番目の引数の数字の1はPHPの文字列型としてキャストされるので明らかに失敗します。
// ...
public function testAssertTrue()
{
$this->assertTrue(5 > 2);
}
// ...
// ...
public function testAssertFalse()
{
$this->assertFalse(5 < 2);
}
// ...
Doctrineはsqlite以外のすべてのドライバ用のモックドライバを使用します。次のコードスニペットはモックドライバの使い方を示します:
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
public function testInit()
{
$this->dbh = new Doctrine_Adapter_Mock('oracle');
$this->conn = Doctrine_Manager::getInstance()->openConnection($this->dbh);
}
}
クエリを実行するときこれらは本当のデータベースに対して実行されません。代わりにこれらは配列に収集され実行されたクエリとそれらに対するテストのアサーションを分析できます。
class Doctrine_Sample_TestCase extends Doctrine_UnitTestCase
{
// ...
public function testMockDriver()
{
$user = new User();
$user->username = 'jwage';
$user->password = 'changeme';
$user->save();
$sql = $this->dbh->getAll();
// 探しているクエリを見つけるためにSQL配列を出力する
// print_r($sql);
$this->assertEqual($sql[0], 'INSERT INTO user (username, password) VALUES (?, ?)');
}
}
すべてのクラスはTestCaseと同等のものを少なくとも1つ持ちDoctrine_UnitTestCaseを継承します。テストクラスはクラスもしくはクラスのアスペクトを参照し、それに応じて命名されます。
例:
メソッドはアジャイルなドキュメントをサポートし何が失敗したのか明確にわかるように名付けられます。これらはテストするシステムの情報も提供します。
例えばメソッドのテスト名としてDoctrine_Export_Pgsql_TestCase::testCreateTableSupportsAutoincPks()は良い名前です。
テストメソッドの名前は長くなる可能性がありますが、メソッドの内容は長くならないようにすべきです。複数のアサート呼び出しが必要なら、メソッドを複数のより小さなメソッドに分割します。ロープもしくは関数の中にアサーションがあってはなりません。
共通の命名規約として使われるTestCase::test[methodName]はDoctrineではされません。ですのでこのケースではDoctrine_Export_Pgsql_TestCase::testCreateTable()は許可されません!
Doctrineのようなソフトウェアのピースにとってユニットテストは非常に重要です。これ無しでは、変更によって既存の作業ユースケースに悪影響があるのかを知るのは不可能です。ユニットテストのコレクションによって変更が既存の機能を壊さないことを確認できます。
次にパフォーマンスを改善する方法を学ぶために移動します。