CakePHPでファイル出力機能のテストをする
みなさんこんにちは。@ryuzeeです。
CakePHPでファイル出力系の機能のテストを行う場合のTipsをご紹介します。
例えばコントローラーの中でこんなファイル出力系の機能があったとします。
function output()
{
$this->lauout = null;
$filename = "test.txt";
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header("Content-Disposition: attachment;filename=" . $filename);
header("Content-Transfer-Encoding: binary");
echo "test1test2test3\n";
return;
}
テストではCakeTestCaseを継承したテストクラスを作成し、testActionメソッドで上記で作成したアクションを呼び出しています。
function testOutput()
{
ob_start(); //※ここが肝
$this->testAction("/tests/output", array('method' => 'get', 'return' => 'result'));
$result = ob_get_contents(); //※
ob_end_clean(); //※
// 適当なテスト
$this->assertTrue(strlen($result) > 0);
$this->assertPattern("/test1test2test3/", $result);
}
肝となるのは以下の点です。
- 実装となっているoutput関数ではヘッダー出力後に標準出力でファイル内に格納する文字列を出力しているので、CakePHPのレンダリングが利用されていないこと
- したがってtestActionの戻り値にはファイルの中身は入ってこない
- なので、testAction実行前に出力バッファのバッファリングを有効にして一旦出力を止め(ob_start)、testAction実行後に出力内容を取得すれば良い(ob_get_contents)
この方式を利用すれば、ファイルダウンロードの機能でも、CakePHPのテストスイートの中でテストが実装でき、ダウンロードされた内容を実際に保存して、他のライブラリで内容を検証したりといった箇所まで自動化できます。 ちなみに僕は、上記の方式でシステムから出力するExcelファイルを別のライブラリを使って検証しています。
なお、CakePHPにおける自動テストでのアンチパターンとして、アプリケーションの中にexit()を入れないことという点があげられます。 CakePHP等テストライブラリを含めてフルスタックになっている場合、exit()するとテストごと終了してしまうためです。 ファイルダウンロード系は最後にexit()している人が多いようなので、そのような箇所がないか確認するようにしてください。
アジャイルコーチングやトレーニングを提供しています
株式会社アトラクタでは、アジャイル開発に取り組むチーム向けのコーチングや、認定スクラムマスター研修などの各種トレーニングを提供しています。ぜひお気軽にご相談ください。
詳細はこちら