間があいてしまいましたが、
の続きです。CakePHP 勉強会で話した内容 のおさらい&より詳細なところです。
何がやりたいか
phpUnderControl は unit test で PHPUnit を使う前提で作られています(というか PHPUnit と同じ phpunit.de で配布されています)が、CakePHP では SimpleTest を使うようになっています。
CI で一番重要だと思われる「テストに失敗した場合に開発者に通知する」というだけを実施したい場合は、
<target name="phpunit"> <exec executable="${basedir}/source/cake/console/cake" dir="${basedir}/source" failonerror="on"> <arg line="testsuite -app ${basedir}/source/app app all"/> </exec> </target>
という感じにしてしまえばいいような気はするんですが(動作は確認してません)、これだけでは phpUnderControl が出力してくれるレポート機能を活かすことができません。
この画像を見てのとおり、上記のタスクを追加しただけでは、
- グラフが真っ白な箇所がある
- テストの NG が拾えていない(すべて OK になっている)
- (この画像からは読み取れませんが)テストの NG 箇所について詳細な情報が閲覧できない
といった点が勿体無いです。
そんなわけで、これらの問題を解決するのが今回の目標です。
レポート生成の流れ
まず、phpUnderControl がレポートやグラフを生成するまでの流れを説明しておきます。
phpUnderControl は build.conf の設定に従って phpDocumentor、PHP_CodeSniffer、PHPUnit 等を呼び出し、その結果を一つの XML ファイル(CruiseControl 配下の logs/<プロジェクト名>/log<タイムスタンプ><ビルド番号>.xml)にまとめます。
その後、この XML を input として、
・JSP 内で XSL を利用したレポートを生成
・phpuc graph 内で DOMXPath を利用したグラフ生成&成否判定
を行っています。(このように二種類の処理があるのですが、以降面倒なのでまとめて XSL と記述します。)
図にすると、だいたいこんな感じです。
さて、SimpleTest でも XML で出力する仕組み(XMLReporter)がありますが、これが作る XML は、残念ながら PHPUnit の XML とは形式が異なります。そのため、XSL による変換で意図どおりの解析ができません。
それを解決しようとすると、二種類の方法があります。
(1) XSL を書き換えて、SimpleTest で作成した XML を読み込めるようにする
ここのコメント欄で軽く触れられていた方法で、おそらくこちらが正攻法です。柔軟性はありますが、SimpleTest でどういうレポートを出力すべきか?という方向性が決まっていないとゴールが見えにくい気がします。(俺フォーマットがたくさんできてしまいそう。)
(2) SimpleTest 側で PHPUnit と同じ構造の XML を吐いてやる
少々胡散臭い方法ですが、うまくいくと PHPUnit のレポートを利用する他のソフトでも、SimpleTest が使えるようになるかもしれません。
(1) はもうやっている人もいるようですし、私は (2) の方法を試してみました。
実際やってみると
PHPUnit とはテストケースの構造が違う(SimpleTest はテストケースがネストした形になる?)ようで、完全に同じ形にするのは大変そうでした。とりあえず XML を読み込む側の設定に無理やり合わせて XML を作ることにします。
具体的には、以下の箇所に XPath 等の記述があるので、その記述に合わせて XMLReporter をカスタマイズします。
- 画面の表示箇所(XSL を使用している箇所)
- path/to/cruisecontrol/webapps/cruisecontrol/xsl 配下の .xsl ファイル
- グラフ描画箇所
ファイル名 | 生成する.svg | グラフの説明 |
---|---|---|
BuildBreakdownInput.php | 01-breakdown-of-build-types | Breakdown of Build Types |
BuildBreakdownTimelineInput.php | 02-breakdown-of-build-timeline | Breakdown of Build Timeline |
UnitCoverageInput.php | 03-unit-coverage | Unit Coverage |
UnitTestInput.php | 04-unit-tests | Unit Tests |
TestCodeRatioInput.php | 05-test-to-code-ratio | Test to Code Ratio |
CodeViolationInput.php | 06-coding-violations | Coding Violations |
UnitTestExecutionTimeInput.php | 07-test-execution-time | Test Execution Time |
- 成否判定箇所
- phpUnderControl/Data/Logs/PHPUnitTestLogAggregator.php
cake testsuite app all
というコマンドがありますが、この動作を少し変えた testreport というシェルを用意して、XMLReporter を利用するようにします。
完成品
XMLReporter のカスタマイズ&testreport シェルの追加を行うパッチです。
対応バージョンは
- CakePHP 1.2.3.8166
- SimpleTest 1.0.1
で、svn diff --summarize でいうと
M vendors\simpletest\xml.php
A cake\console\libs\testreport.php
こんな感じの構成になっていますので、SimpleTest を vendors/simpletest に展開しておく必要があります。
使い方
上記のパッチを適用後、以下の編集を行う必要があります。
cake\console\libs\testreport.php 内に出力先のパスがベタ書きされていますので、
file_put_contents('path/to/project/build/logs/phpunit.xml', ob_get_contents());
の行を編集してください。
その後、build.xml を編集します。
<target name="phpunit"> <exec executable="${basedir}/source/cake/console/cake" dir="${basedir}/source" failonerror="on"> <arg line="testreport -app ${basedir}/source/app app all"/> </exec> </target>
といった感じで使えるはずです。(cake に実行権限をつけておく必要があります。)
なお、testreport.php は testsuite.php を元にしたファイルですので、SVN でちゃんと管理したい方は
svn cp cake\console\libs\testsuite.php cake\console\libs\testreport.php
としたあとで testreport.php を削除→パッチ適用といった流れで作業するといいかもしれません。
配布形態について
本当は
- CakePHP 本家のソースを fork
- SimpleTest をそこにコピー
- 必要な変更を実施
という流れで行おうと思っていたんですが、ライセンス周りが面倒なのでパッチ形式での配布にしています。
何が面倒かというと、
- CakePHP は MIT License
- SimpleTest は LGPL(Open Group Test Suite License も併記されていたけど詳細不明)
となっており、CakePHP のリポジトリに LGPL のソースが混入するのを避けたかったからです。
(元々 GPL や LGPL は PHP のような形態を想定していないライセンスなので、どう扱うのが適切なのかよくわかりません。XMLReporter を元にせず一から作りなおせば、ライセンスなんか気にしなくていいんでしょうけど。)
改善できた点/できなかった点
現状ではこんな感じです。
- テストの NG をビルドエラー扱いにできるようになった
- テストの件数が拾えるようになった
- Unit Tests のグラフと、Test to Code Ratio のグラフのテストに関する項目が表示された
- テストの NG 箇所について詳細な情報が拾えるようになった
今後の課題として、
- テストのレポートをまじめに整形する
- 内容によってはこんな感じ(横幅 2600 px とか)でデザインが崩れてしまいます
- テストの所要時間を取得する
といった点が挙げられます。
また、最低限の変更しか行っていないため、以下の点で保守性が悪くなっています。
- 出力先のパスをベタ書きしてある
- ob_xxxxxx で無理やりファイルに吐き出している
- 元々標準出力に吐く形で実装されていたが、変更点を少なくするためこの形で実装しています
あくまでも参考にとどめて、新しく Reporter を書き直す/XSL に手を入れるほうが手っ取り早いかもしれません。