CakePHP ファイル出力機能のテストをする

 2010/11/14

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()している人が多いようなので念のため。

 2010/11/14

サイト内検索


著作

寄稿

Latest post: