今回は、PHPUnit3の便利な機能とPHP版プロジェクトビルドシステムであるPhingとの連携について見ていきます。
既存クラスからテストを作成する
さて、別の開発チームで作成していた決済用クラス(Checkoutクラス)が届きました。
しかし、テストが用意されていません。これもありがちな話…でしょうか。このCheckoutクラスに対してもテストを用意しておきたいところですが、1から作成するのはちょっと面倒です。
PHPUnit3には既存クラスから自動的にテストケースを生成するジェネレータが用意されています。今回はこれを使ってテストケースを作ってみましょう。
既存クラスからテストケースを生成するには、phpunitコマンドに「--skeleton」オプションとクラス名を指定します。
生成されたCheckoutTest.phpは以下の通りです。
生成されたCheckoutTest.phpのtestXXXXXメソッドを見てみると、markTestIncompleteメソッドが呼び出されていることが分かります。このメソッドは、名前の通り、そのテストがまだ完成していないことを表すために使われます。実際にCheckoutTestを実行してみると、テスト結果に「I」と表示されることが分かります。
それでは、CartクラスとCartTest.php、CheckoutTest.phpの両テストを修正していきます。まずはCartクラスです。CartクラスにはCheckoutオブジェクトを返すcheckoutメソッドを追加しましょう。
また、テストは次のように記述しました。
それでは、Cart側のテストを実行してみます。
それでは、checkoutメソッドを実装します。単純にCheckoutオブジェクトを生成して返すだけのコードです。
<?php
class Cart
{
:
public function checkout() {
include_once 'Checkout.php';
return new Checkout($this);
}
}
それではテストを実行します。
問題なさそうです。
それでは、CheckoutTestクラスの修正に入ります。ここではgetShippingChargeメソッドの境界値テストがポイントになりそうですね。また、Cartクラスはすでに存在していますので、これを使ってモックオブジェクトを生成し、テストを行うことにします。
以下が、修正後のテストケースの抜粋です。
テストを実行してみます。
こちらが想定したテストをすべてクリアしています。
複数のテストをまとめて実行する
ここまで2つのテストケースを作成し、それぞれテストを実行してきましたが、テストケースが増えてくると個別に実行していては時間がいくらあっても足りません。PHPUnitにはスイート(Suite)と呼ばれる、テストをまとめて実行する仕組みが用意されています。
最も簡単なスイートのコードは、以下のようになります。
ポイントは2つあります。
- PHPUnit_Framework_TestSuiteのインスタンスを返すpublic static suiteというメソッドを用意する
- suiteメソッドの中で実行するテストを追加する
スイートの実行はテストケースの実行と同様、phpunitコマンドにクラス名(必要であれば、ファイル名も)を指定します。
今まで作成した16個すべてのテストが一度に実行されていることが分かるでしょうか?また、あるスイートを別のスイートにまとめて実行する事もできます。この場合、addTestSuiteメソッドに代わりにaddTestメソッドを使用します。以下は少々冗長ですが、先のスイートを2つのスイートに分けたコードです。
phingとの連携
ここまでPHPUnit3の機能を色々と見てきましたが、Phingというプロジェクトビルドシステムと組み合わせることで、さらに使いやすくなります。
プロジェクトビルドシステムで有名なものとしては、Apache Antを元にして作られています。Apache AntはJavaソースファイルのコンパイルやテストの実行、APIドキュメント(javadoc)の作成などを「タスク」と呼ばれる単位で定義されており、タスクを組み合わせることで様々なバッチ処理を行うことができるようになっています。Phingは、このApache Antを元にして作られており、Apache Antと同様に、テストの実行やphpDocumentorを使ったAPIドキュメントの作成など、様々なツールと連携したバッチ処理を行うことができます。
インストール
PhingはPEARパッケージとして提供されていますので、pearコマンドでのインストールが可能です。具体的には、以下の通りとなります。今回はバージョン2.3.0beta1を使用しました。
インストール後、phingコマンドが利用可能になっていることを確認しておきます。
build.xml
Phingは、デフォルトではbuild.xmlというXMLファイルに実行するタスクやバッチ処理を定義することになります。
まずは、簡単な例をお見せします。
このbuild.xmlは、カレントディレクトリにある*Test.phpというファイルに対してphpunitを実行するものですが、ここでそれぞれの要素について触れておきます。まず、build.xmlのルート要素はproject要素です。属性として、プロジェクト名や基準となるディレクトリ、phingコマンドに引数が渡されなかった場合に実行する処理(target要素で定義。後述)を指定しています。
project要素の子要素として定義しているのがtarget要素です。このtarget要素を使って、様々なタスクをまとめます。
また、上記のbuild.xmlではname属性に「test」を指定していますが、この名前をphingコマンドの引数に指定すると、特定のtargetを実行することができます。
target要素の子要素には「タスク」を指定します。Phingには数多くのタスクが用意されています。上記build.xmlではPHPUnitと連携するphpunit2タスクが含まれています。
それぞれのタスクには子要素を指定できるものがあります。phpunit2タスクも、batchset要素や、さらにその子要素としてfileset要素、include要素などを使用することができます。ここでは、指定したディレクトリ以下にある、特定のパターンにマッチするファイルを対象にテストを行うように記述されています。
なお、PhingにはAPIドキュメントを作成する「phpdoc」タスクのほか、tarやzipを使ったアーカイブの作成、Subversionとの連携など様々なタスクが用意されています。それぞれのタスクの詳細については、PhingのUser Guideを参照してください。
さて、このbuild.xmlを使って、phingを実行してみましょう。
いかがでしょうか?テストスイートを使わずに、今まで作成したテストが全て実行されている事が分かると思います。
確かに、PHPUnitのテストスイートを使うことで全てのテストを実行することができるのですが、テストケースを追加するたびにテストスイートを修正する必要があります。このため、テストの実行漏れが問題になる可能性があります。その点、上記のように*Test.phpを対象とするテストが可能になります。
また、テスト結果をHTML形式で出力することも可能です。これには、phpunit2タスクでサポートされているformatterタグとphpunitreportタスクを使用します。以下のbuild.xmlは、先ほどのbuild.xmlにphpunit2タスク・formatterタグ・phpunitreportタスクを適用した例となります。テストを実行し、レポートをカレントディレクトリ直下のreports/testsディレクトリに出力します。
formatterタグ・phpunitreportタスクのその他詳細については、Phingマニュアルを参照してください。
このbuild.xmlを実行してみます。
実行結果は先のものと変わりませんが、mkdirタスクで作成したreports/testsディレクトリにHTMLファイルやCSSファイルが作成されていることを確認してください。確認できたら、index.htmlをブラウザで開くと次のような表示がされるはずです。
さらに、カバレッジ解析の結果もHTML形式で出力することも可能です。これにはcoverage-setupタスクとcoverage- reportタスクを使用します。さらに、phpunitタスクのcodecoverageオプションをtrueに設定します。以下は、先ほどのbuild.xmlにカバレッジ解析に関連する設定を追加したものになります。カバレッジ結果は、カレントディレクトリ直下のreports/coverageディレクトリに出力されます。
なお、各タスクの詳細については、Phingマニュアルを参照してください。
しかし、PHPUnit3.1.7にはカバレッジ結果の出力に不具合があり、正しいカバレッジ結果が出力されません。具体的には、PHPUnitTestRunnerクラス([PEARディレクトリ]/phing/tasks/ext/phpunit/PHPUnitTestRunner.php)のrunメソッドでカバレッジ結果をマージしているのですが、その引数が間違っているために発生します。そこで、以下のように修正し、正しくカバレッジ結果を渡すよう修正しておきます[1]。
修正したら、早速このbuild.xmlを実行してみましょう。
実行後、mkdirタスクで作成したreports/coverageディレクトリにHTMLファイルやCSSファイルが作成されていることを確認してください。確認できたら、index.htmlをブラウザで開くと次のような表示がされるはずです。
なお、PHPUnit3とPhingでカバレッジの対象とする行のカウント方法が異なるため、結果のパーセンテージが変わってしまうことに注意してください。
Phingには紹介したタスク以外に、APIドキュメントの生成やsvnへのアクセス、PHPスクリプトの構文チェックなど様々なタスクが用意されています。また、独自タスクも作成可能です。Phingとうまく組み合わせ、効果的にプロジェクトをビルドしていきましょう。