長らくやろうやろうと思っていながら手がつかなかったCakePHP3のユニットテストについて。
以前にも何らかのエントリーで書いたのですが(下記参照)、モデル系はなかなかやらなかったので、これを機に説明させていただきます。
CakePHP3系でのテスト処理
CakePHP3でのコレクションに関して(厳密にはテストではないですが、デバッグに便利)
注意点ですがなんといっても「テスト用のテーブルはドロップされる」でしょう。初期化ではなく、テーブル自体がなくなってしまいます。
これが何といっても一番注意しなくてはいけないでしょう。設定ファイル(下記参照)で設定されたテスト用のデータベースですが、なんとデータベースはドロップされます。
1 2 3 4 5 6 7 8 |
'test' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Mysql', 'persistent' => false, 'host' => 'ホスト名', 'database' => 'データベース名' ・・・・・・・・・・・・・・・・・・・・・・・・・・・・・ ], |
これはデータベースのテストという観点から考えると当たり前かもしれません。
データベース系のテストの場合、なんといっても前提条件となる状態を保存しておくことが大切になります。
そのため下記のような手順が本来は望ましいです。
- 内部のデータを一度保存
- データベースを初期化
- 前提となるデータを入れる
- テストを行う
- 1で保存したデータをリストアする
参考(DBUnit)
http://skill-up-engineering.com/?p=924
Cakeの場合2~5が実行されることになります。
知らないで使っているデータベースをつなぐとえらいことになるので気を付けましょう。
Fixture
また上記のステップ3で使用する前提となるデータですがFixtureというクラスで定義されています。
ディレクトリは/tests/Fixtureです。※最初はbakeで作るのが良いと思います。
ここに入っているデータがテスト中は一時的に取り込まれますが、テストを行うとそもそもテーブル自体がドロップされますのでデバッグして途中で止めない限りはわかりません。
Fixtureを作るのはbakeが一番楽でしょう。よく考えるとテーブルの状態も変わっていくことがほとんどなので実際のテーブルを持たずに、都度更新しておいたほうが理にかなっています。
また上記の2~5のステップは1テストごとに実行されるのでそれぞれのメソッドでの状態変化は考えなくてもよいです。
ソース
超簡単なテストですが、Fixtureと実際のモデルのテストケースのソースを記述させていただきます。
Fixture
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
<?php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; /** * CustomersFixture * */ class CustomersFixture extends TestFixture { /** * Fields * データベースの構造がここに入ります。 * @var array */ // @codingStandardsIgnoreStart public $fields = [ 'id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false, 'default' => null, 'comment' => '', 'autoIncrement' => true, 'precision' => null], 'code' => ['type' => 'string', 'length' => 100, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], 'name' => ['type' => 'string', 'length' => 255, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null, 'fixed' => null], 'note' => ['type' => 'text', 'length' => null, 'null' => true, 'default' => null, 'collate' => 'utf8_general_ci', 'comment' => '', 'precision' => null], 'created_user' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], 'created' => ['type' => 'timestamp', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 'modified_user' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'autoIncrement' => null], 'modified' => ['type' => 'timestamp', 'length' => null, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null], 'is_delete' => ['type' => 'boolean', 'length' => null, 'null' => false, 'default' => '0', 'comment' => '', 'precision' => null], '_constraints' => [ 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], ], '_options' => [ 'engine' => 'InnoDB', 'collation' => 'utf8_general_ci' ], ]; // @codingStandardsIgnoreEnd /** * Records * 実際にはいる前提となるデータがここに入ります。 * @var array */ public $records = [ [ 'id' => 1, 'code' => 'sampleCode', 'name' => 'sampleName', 'note' => '', 'created_user' => 1, 'created' => 1480326627, 'modified_user' => 1, 'modified' => 1480326627, 'is_delete' => 0 ], [ 'id' => 2, 'code' => 'sampleCode2', 'name' => 'sampleName2', 'note' => '', 'created_user' => 1, 'created' => 1480326627, 'modified_user' => 1, 'modified' => 1480326627, 'is_delete' => 0 ], ]; } |
テストケース
※実際にはテストはしておらず単なるデバッグですが・・・
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<?php namespace App\Test\TestCase\Model\Table; use App\Model\Table\CustomersTable; use Cake\ORM\TableRegistry; use Cake\TestSuite\TestCase; /** * App\Model\Table\CustomersTable Test Case */ class CustomersTableTest extends TestCase { /** * Test subject * * @var \App\Model\Table\CustomersTable */ public $Customers; /** * Fixtures * ここに記述することにより * Fixtureが読み込まれます。 * @var array */ public $fixtures = [ 'app.customers', ]; /** * setUp method * * @return void */ public function setUp() { parent::setUp(); $config = TableRegistry::exists('Customers') ? [] : ['className' => 'App\Model\Table\CustomersTable']; $this->Customers = TableRegistry::get('Customers', $config); } /** * tearDown method * * @return void */ public function testGetRecord(){ $arr = $this->Customers->find('all')->hydrate(false)->toArray(); //var_dumpするとFixtureのデータを見ることができます。 } } |