PHP
CakePHP 3.2.3
CakePHP3 PHPUnit テーブルが消える
CakePHPでのユニットテストに取り組んでおります。
まだまだやり始めたばっかりなので、いろいろと間違っているところもあると思いますが、詳しい人はぜひ教えてください。
さて、いきなり全体のテストではなく、まずは試しにモデルのテストを作ってみます。
//テストする対象のモデル //Model/Table/OffersTable.php class OffersTable extends Table { //前略 public function findApproved(Query $query, array $options){ $query->where([ 'Offers.status' => 'approved' ]); $query->select(['id', 'status']); return $query; } //後略 }
//上記のメソッドのテストを作ります //tests/TestCase/Model/Table/OffersTableTest.php <?php namespace App\Test\TestCase\Model\Table; use App\Model\Table\OffersTable; use Cake\ORM\TableRegistry; use Cake\TestSuite\TestCase; /** * App\Model\Table\OffersTable Test Case */ class OffersTableTest extends TestCase { public $Offers; public $fixtures = [ 'app.offers' ]; public function setUp() { parent::setUp(); $config = TableRegistry::exists('Offers') ? [] : ['className' => 'App\Model\Table\OffersTable']; $this->Offers = TableRegistry::get('Offers', $config); } public function tearDown() { unset($this->Offers); parent::tearDown(); } public function testInitialize() { $this->markTestIncomplete('Not implemented yet.'); } public function testValidationDefault() { $this->markTestIncomplete('Not implemented yet.'); } public function testBuildRules() { $this->markTestIncomplete('Not implemented yet.'); } public function testFindApproved() { $query = $this->Offers->find('approved'); $this->assertInstanceOf('Cake\ORM\Query', $query); $result = $query->hydrate(false)->toArray(); $expected = [ ['id' => 2, 'status' => 'approved'], ]; debug($result); $this->assertEquals($expected, $result); } }
設定ファイルに、テスト用のDBの設定を書いておきます。
'Datasources' => [ /** * The test connection is used during the test suite. */ 'test' => [ 'className' => 'Cake\Database\Connection', 'driver' => 'Cake\Database\Driver\Mysql', 'persistent' => false, 'host' => 'localhost', 'username' => 'my_app', 'password' => 'secret', 'database' => 'test_myapp', 'encoding' => 'utf8', 'timezone' => 'UTC', 'cacheMetadata' => true, 'quoteIdentifiers' => false, 'log' => false, ], ],
サーバーで、次のようにphpunitを実行します。
phpunit --filter testFindApproved tests/TestCase/Model/Table/OffersTableTest
次のように、Failureが返ってきます。
PHP Warning: Module 'intl' already loaded in Unknown on line 0 PHPUnit 5.2.9 by Sebastian Bergmann and contributors. F 1 / 1 (100%)/tests/TestCase/Model/Table/OffersTableTest.php (line 88) ########## DEBUG ########## [] ########################### Time: 149 ms, Memory: 12.00Mb There was 1 failure: 1) App\Test\TestCase\Model\Table\OffersTableTest::testFindApproved Failed asserting that two arrays are equal. --- Expected +++ Actual @@ @@ Array ( 0 => Array ( - 'id' => 2 + 'id' => 24 'status' => 'approved' ) ) /var/www/html/gildotcom/tests/TestCase/Model/Table/OffersTableTest.php:89 FAILURES! Tests: 1, Assertions: 2, Failures: 1.
ま、これは予想されたことなのでよいのですが、問題は、test_myappデータベースから、offers というテーブルが消えてしまったことです。
は??(・A・) Oh My God!!となりますね。私の場合は、別に開発中のサーバーだったので、無問題なのですが…。
犯人は、こ・い・つ!
public $fixtures = [ 'app.offers' ];
Fixtureというやつですね。
これを指定しているので、
tests/Fixture/OffersFixture.php
にある、次のフィクスチャーにあるデータが実行されていたようです。
<?php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; /** * OffersFixture * */ class OffersFixture extends TestFixture { // @codingStandardsIgnoreStart public $fields = [ 'id' => ['type' => 'string', 'length' => 64, 'null' => false, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 'status' => ['type' => 'string', 'length' => 16, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 'winner_id' => ['type' => 'string', 'length' => 64, 'null' => true, 'default' => null, 'comment' => '', 'precision' => null, 'fixed' => null], 'work_type_id' => ['type' => 'integer', 'length' => 11, 'unsigned' => false, 'null' => false], //以下略 ]; // @codingStandardsIgnoreEnd public $records = [ [ 'id' => '24a1f938-c898-4376-8a05-b8d6a614dda7', 'status' => 'approved', 'winner_id' => 'Lorem ipsum dolor sit amet', 'work_type_id' => 1, 'created' => '2016-02-02 11:22:24', 'modified' => '2016-02-02 11:22:24' ], ]; }
そんで、そのあとDBのテーブルがDropされていた。と。
フィクスチャーはテストの際に、実際のデータに影響を与えないように、仮のテスト用データを作れるという機能です。
上記では、class OffersFixtureでデータのフィールドと、実際のデータを作っているわけですね。
下記の公式ページに
http://book.cakephp.org/3.0/en/development/testing.html#creating-a-test-method
CakePHP performs the following during the course of a fixture based test case:
・Creates tables for each of the fixtures needed.
・Populates tables with data, if data is provided in fixture.
・Runs test methods.
・Empties the fixture tables.
・Removes fixture tables from database.
要は
「そのテーブル 消えるよ」
と言ってくれていたのですが、仮のデータが消されるのかと思ってましたよ…(つД`)
本当に、テスト用のデータベースのテーブルを消すんですね!!Cake先輩!!
ちなみに、bake で自動でテストコード作ると、このように自動でFixtureを作ってくれて、Fixtureを使うようになっています。
bakeしたみなさん、ご注意を!!
app.phpのテストDBの設定を、
「本物のデータでテストしてみよー」
とか気軽に考えて、気軽に実行すると、データが全部消えることになりますから。
ということで、public $fixtures をOffersTabteTest.phpから消去し、再び
phpunit --filter testFindApproved tests/TestCase/Model/Table/OffersTableTest
すると、test_myAppDBからoffersテーブルを読み込み、次のように結果がOKとなります。
PHP Warning: Module 'intl' already loaded in Unknown on line 0 PHPUnit 5.2.9 by Sebastian Bergmann and contributors. 1 / 1 (100%)/tests/TestCase/Model/Table/OffersTableTest.php (line 87) ########## DEBUG ########## [ (int) 0 => [ 'id' => (int) 2, 'status' => 'approved' ] ] ########################### Time: 189 ms, Memory: 12.00Mb OK (1 test, 2 assertions)
テーブルもきえませんでした! ⊂(^-^)⊃