CakePHPでモデルのUnitTestを行う


# モデルを作成
* app/Model/Article.phpを作成

```php
<?php
class Article extends AppModel {
    public function published($fields = null) {
        $params = array(
            'conditions' => array(
                $this->name . '.published' => 1
            ),
            'fields' => $fields
        );

        return $this->find('all', $params);
    }
}
```

# フィクスチャを作成
* テストに使うための一時的なデータをロードするためのもの
* 実データを使わずにデータベースが必要な機能をテストできる
* app/Test/Fixture配下に作成する([Model名]Fixture)
* app/Config/database.phpにある$testのデータベース接続情報を使う
* フィクスチャでは以下の2点を記述する
	* フィールド情報
	* 初期状態で用意するレコードデータ

```php
<?php
class ArticleFixture extends CakeTestFixture {
  	  public $fields = array(
          'id' => array('type' => 'integer', 'key' => 'primary'),
          'title' => array(
            'type' => 'string',
            'length' => 255,
            'null' => false
          ),
          'body' => 'text',
          'published' => array(
            'type' => 'integer',
            'default' => '0',
            'null' => false
          ),
          'created' => 'datetime',
          'updated' => 'datetime'
      );
      public $records = array(
          array(
            'id' => 1,
            'title' => 'First Article',
            'body' => 'First Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:39:23',
            'updated' => '2007-03-18 10:41:31'
          ),
          array(
            'id' => 2,
            'title' => 'Second Article',
            'body' => 'Second Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:41:23',
            'updated' => '2007-03-18 10:43:31'
          ),
          array(
            'id' => 3,
            'title' => 'Third Article',
            'body' => 'Third Article Body',
            'published' => '1',
            'created' => '2007-03-18 10:43:23',
            'updated' => '2007-03-18 10:45:31'
          )
      );
 }
```

* テストデータベース以外の既存のデータベース(デフォルトテーブル)を利用したい場合

```php
      //デフォルトテーブルに存在するテーブルのフィールド情報を読み込む
      public $import = ['table' => 'articles'];
      public $records = [];
```

* 上記のようにしておくと既存テーブルの構成を使ってデータが生成される

# テスト用クラスを作成
* app/Test/Case/Model/[Model名]Test.php


```php
<?php
//テスト対象のモデルをインポート
App::uses('Article', 'Model');
//外部ライブラリ
App::uses('Fabricate', 'Fabricate.Lib');

class ArticleTest extends CakeTestCase {
    public $fixtures = array('app.article');

    //テスト実行前に毎回呼ばれる
    public function setUp() {
        //親のsetUpは必ず呼び出す
        parent::setUp();
    }

    //testXXの名前にする
    public function testPublished() {
        $expected = array(
            array('Article' => array('id' => 1, 'title' => 'First Article')),
            array('Article' => array('id' => 2, 'title' => 'Second Article')),
            array('Article' => array('id' => 3, 'title' => 'Third Article'))
        );
        //モックを使うパターン
        $model = $this->getMockForModel('Article', array('published'));
        //先に呼び出す回数と期待する値をセット
        $model
            ->expects($this->once())
            ->method('published')
            ->will($this->returnValue($expected));
        //実行する
        $result = $model->published(array('id', 'title'));

        //テーブルにモックデータを保存して結果を返す。実際のテーブルに保存されるわけではない
        //件数指定しない場合は1件
        Fabricate::create('Article', function($data, $world) {
            //取得結果を変更したり出来る
            return [
                'id' => 1
                'name' => 'test'
            ];
        });
        $articles = $this->Article->find('all');
    }
}
```

* 事前に用意したデータだけでテストするのであれば、フィクスチャでレコードを用意しておくだけでいいが、自分でテストデータを追加したりしたい時も多い
* そんな場合はこのライブラリを使う。作成されるデータはスキーマ情報から自動判定されて適当な初期値が入る
* 値を変えたい場合は、コールバックで変更が可能
* 作成する件数は第二引数で指定できる。デフォルトは1件
https://github.com/sizuhiko/Fabricate