"Key (id)=(1) already exists" error occurred in CakePHP3 model test.
久々にCakePHP でテストを書いている。
Fixture を整えて、TestCase を書いた。
そして、値を save するメソッドをテストした。
すると、
duplicate key value violates unique constraint "hoges_pkey" DETAIL: Key (id)=(1) already exists.
というエラーが出た。
悲しい。
書いてたFixture は、こんな感じ。
<?php namespace App\Test\Fixture; use Cake\TestSuite\Fixture\TestFixture; class HogesFixture extends TestFixture { /** * Fields * * @var array */ // @codingStandardsIgnoreStart public $fields = [ 'id' => ['type' => 'integer', 'length' => 10, 'autoIncrement' => true, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'unsigned' => null], 'user_id' => ['type' => 'integer', 'length' => 10, 'default' => null, 'null' => false, 'comment' => null, 'precision' => null, 'unsigned' => null, 'autoIncrement' => null], 'fuga' => ['type' => 'text', 'length' => null, 'default' => null, 'null' => false, 'collate' => null, 'comment' => null, 'precision' => null], 'modified' => ['type' => 'timestamp', 'length' => null, 'default' => null, 'null' => true, 'comment' => null, 'precision' => null], 'deleted' => ['type' => 'timestamp', 'length' => null, 'default' => null, 'null' => true, 'comment' => null, 'precision' => null], '_constraints' => [ 'primary' => ['type' => 'primary', 'columns' => ['id'], 'length' => []], ], ]; // @codingStandardsIgnoreEnd /** * Init method * * @return void */ public function init() { $this->records = [ [ 'id' => 1, 'user_id' => 1, 'fuga' => 'a', 'modified' => 1539138087, 'deleted' => 1539138087 ], [ 'id' => 2, 'user_id' => 1, 'fuga' => 'b', 'modified' => 1539138087, 'deleted' => 1539138087 ], [ 'id' => 3, 'user_id' => 1, 'fuga' => 'c', 'modified' => 1539138087, 'deleted' => 1539138087 ], ]; parent::init(); } }
そして、原因は Fixture にあった。
解決策は、
public function init() { $this->records = [ [ // 'id' => 1, 'user_id' => 1, 'fuga' => 'a', 'modified' => 1539138087, 'deleted' => 1539138087 ], [ // 'id' => 2, 'user_id' => 1, 'fuga' => 'b', 'modified' => 1539138087, 'deleted' => 1539138087 ], [ // 'id' => 3, 'user_id' => 1, 'fuga' => 'c', 'modified' => 1539138087, 'deleted' => 1539138087 ], ]; parent::init(); }
$this->records に入れた連想配列内の、 id を消すこと。
普通に考えたらそうだ。
ID は、 データベースのsequenceの機能を使うので、idの発行をCakePHPに任せたら、
1からID が付与され、自動的にインクリメントされる。
一方、ID に値を入れてしまうと、Database の Sequence の機能を使わずに値が保存される。
よって、Database は、次の値は1だと思っている。しかし、1はすでに存在している。
だから、エラーになる。
細かいところだが、ハマりどころだ。
やっかいなことに、 Fixture を bake すると、デフォルトで値が挿入されるので、
Bake のテンプレートを書き換えるか (やったことない) いちいちコメントアウト (もしくは削除) する必要がある。
参考にしたのはこちら stackoverflow.com