miauのブログ

はてなダイアリー「miauの避難所」をはてなブログに移行しました

phpUnderControl で CakePHP を使う

間があいてしまいましたが、

の続きです。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 は、残念ながら PHPUnitXML とは形式が異なります。そのため、XSL による変換で意図どおりの解析ができません。

それを解決しようとすると、二種類の方法があります。

(1) XSL を書き換えて、SimpleTest で作成した XML を読み込めるようにする


ここのコメント欄で軽く触れられていた方法で、おそらくこちらが正攻法です。柔軟性はありますが、SimpleTest でどういうレポートを出力すべきか?という方向性が決まっていないとゴールが見えにくい気がします。(俺フォーマットがたくさんできてしまいそう。)

(2) SimpleTest 側で PHPUnit と同じ構造の XML を吐いてやる

少々胡散臭い方法ですが、うまくいくと PHPUnit のレポートを利用する他のソフトでも、SimpleTest が使えるようになるかもしれません。

(1) はもうやっている人もいるようですし、私は (2) の方法を試してみました。

実際やってみると

PHPUnit とはテストケースの構造が違う(SimpleTest はテストケースがネストした形になる?)ようで、完全に同じ形にするのは大変そうでした。とりあえず XML を読み込む側の設定に無理やり合わせて XML を作ることにします。

具体的には、以下の箇所に XPath 等の記述があるので、その記述に合わせて XMLReporter をカスタマイズします。

  • 画面の表示箇所(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

また、CakePHP には CUI で全テストを実施する

cake testsuite app all

というコマンドがありますが、この動作を少し変えた testreport というシェルを用意して、XMLReporter を利用するようにします。

完成品

XMLReporter のカスタマイズ&testreport シェルの追加を行うパッチです。

対応バージョンは

で、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
  • SimpleTestLGPL(Open Group Test Suite License も併記されていたけど詳細不明)

となっており、CakePHPリポジトリLGPL のソースが混入するのを避けたかったからです。
(元々 GPLLGPLPHP のような形態を想定していないライセンスなので、どう扱うのが適切なのかよくわかりません。XMLReporter を元にせず一から作りなおせば、ライセンスなんか気にしなくていいんでしょうけど。)

改善できた点/できなかった点

現状ではこんな感じです。


  • テストの NG をビルドエラー扱いにできるようになった
  • テストの件数が拾えるようになった
    • Unit Tests のグラフと、Test to Code Ratio のグラフのテストに関する項目が表示された
  • テストの NG 箇所について詳細な情報が拾えるようになった

今後の課題として、

  • テストのレポートをまじめに整形する
    • 内容によってはこんな感じ(横幅 2600 px とか)でデザインが崩れてしまいます

  • テストの所要時間を取得する

といった点が挙げられます。

また、最低限の変更しか行っていないため、以下の点で保守性が悪くなっています。

  • 出力先のパスをベタ書きしてある
  • ob_xxxxxx で無理やりファイルに吐き出している
    • 元々標準出力に吐く形で実装されていたが、変更点を少なくするためこの形で実装しています

あくまでも参考にとどめて、新しく Reporter を書き直す/XSL に手を入れるほうが手っ取り早いかもしれません。

その他できなかったこと

ついでに今後こういうのも使いたいなー、と考えていたツールについても書いておきます。私はしばらく PHP 案件に係わらない予感がするので、気が向いた方は試してみてください。

phpmd や phpcpd を使えば PHPUnit PMD 相当のことができるかも。

PHP の software metrics ツール。phpUnderControl 作者(?)の Manuel Pichler 氏は最近こっちに注力しているらしい。