2010年1月8日金曜日

CakePHPでテストする時にFixtureのデータを再利用してDRYにしよう

DRYはDon't repeat yourself。コードの重複を省くこと

CakePHPのbakeで生成されたテストは微妙というより、そのままでは使えない。とくに$expectedのところ。

function testUserFind() {
  $this->User->recursive = -1;
  $results = $this->User->find('first');
  $this->assertTrue(!empty($results));
//ここ!
  $expected = array('User' => array(
    'id'  => 1,
    'name'  => 'Lorem ipsum dolor sit amet',
    'created'  => 'Lorem ipsum dolor sit amet',
    'modified'  => 'Lorem ipsum dolor sit amet'));

  $this->assertEqual($results, $expected);
}

// こうしたい
function testUserFind() {
  $this->User->recursive = -1;
  $results = $this->User->find('first');
  $this->assertTrue(!empty($results));
  $this->assertEqual($results, $this->UserFixture->records[0]);
}

この$expectedで定義している配列はFixtureでも定義しているんだし、そもそもFixtureで入れたデータをもとに検証するのだから、ここではそのままFixtureを利用すれば良いだけの話のはずなんだけど。。。

App::importでFixtureを呼び出す

やり方は簡単です。

//user.test.php)
// ..省略
App::import('Fixture', 'User');

class UserTestCase extends CakeTestCase {
//..省略
  function startTest(){
  //..省略
    $this->UserFixture =&  ClassRegistry::init('UserFixture');
  //
}
これで上記の「こうしたい」コードで動くようになります。

さらにコードの品質を上げる

コードの読みやすさも大事ですが、分かりやすさも大事です。そしてPHP配列の場合順番が変わる可能性がある(やり方次第だけど)のと、文字列を使って意味を明確するために連想配列を使うことをおすすめします。それと、Fixtureの$records以外はデータベースに挿入されないので、save時のテストデータや不正なデータなどはプロパティを分けて用意します。こんな感じ。。。

//user_fixture.php
class UserFixture extends CakeTestFixture{
  var $records = array('admin' => array(
    'id' => 1,
    'name' => 'Admin',
    'flag_admin' => 1,
    'created' => '2010-01-08 05:19:23',
    'updated' => '2010-01-08 05:24:52'
  ));

  // 不正なデータはIDを400〜499にするとかルール漬けして下さい!
  // 500台はインジェクションコードを埋め込んだデータとかね!
  var $invalids = array('name' => array(
    'id' => 400,
    'name' => null,
    'flag_admin' => 1,
    'created' => '2010-01-08 05:19:23',
    'updated' => '2010-01-08 05:24:52'
  ));
}

// user.test.php
//Fixtureの利用の仕方は上記参照
//名前が空の不正なデータの場合のテスト(バリデーション設定済みという設定)
class UserTestCase extends CakeTestCase{
  function testSaveInvalidNameUser(){
    $this->User->create();
    $this->User->set($this->UserFixture->invalids['name']);
    $this->assertFalse($this->User->save());
  }
}

残念なことに、このサンプルコード自体はテストしてないので動くか分かりませんが、雰囲気はつかめると思います。Fixtureを修正した時にテストコードの$expectedを修正する作業が減ります。メンテナンス性が向上しますね。

※ empty関数のところが!emptyemptyになってるのはコードハイライターのバグです

1 件のコメント:

DBTool Super さんのコメント...

Excelでデータベースの取り込みやのデータ取得/更新するなら、ExcelDBToolをお勧めします。
テーブルのデータをエクセルに取得、更新、削除することだけではなく、複数のSQLを実行して、結果を
一括Excelの各シートに出力することもできます。

http://www.superdbtool.com
ベクターからもダウンロードできます。
Oracle,SQL Server,DB2,Sybase,MySQL,Postgre,Sqlite対応。

使い方動画:
http://superdbtool.com/blog/basic-guide

またExcelDBToolを使って、本番擬似ランダムテストデータを一括作成することは非常に簡単です。
是非お試しください。
作成できるダミーデータ種類(69種類):
郵便番号, 都道府県, 企業名, 市区,町村,最寄駅,最寄駅ふりがな,路線,銀行コード, 銀行名, 銀行カタカナ, 支店コード, 支店名, 支店カタカナ,E-Mail, URL, 携帯, 苗字のみ, 氏名, 住所, 住所ふりがな,性別, 年齢, 血液型, 固定電話, 婚姻, ふりがな, 大学名,身長,体重固定値,国籍,国籍英語,国籍英語略,クレジットカード会社,クレジットカード番号,有効期限,IPアドレス,業種大分類,業種大分類名称,業種中分類,業種中分類名称,業種小分類,業種小分類名称,職種大分類,職種大分類名称,職種中分類,職種中分類名称,職種小分類,職種小分類名称,数値連番,整数・小数点数,英数混在,文字列+連番,文字列+全角連番全角漢字,ひらがな,全角カタカナ,半角カタカナ,全角英数,全角数値,全角英字,全半混在日付,時間,タイムスタンプ,特殊文字

Oracle,SQL Server,DB2,Sybase,MySQL,Postgre,Sqliteもご利用できます。