CakePHP4.3 より、これまでのフィクスチャマネージャーが非推奨になり、フィクスチャファクトリの利用が推奨されています。
フィクスチャのスキーマとデータ管理の責務が分割を目的とし、フィクスチャの複雑化の防止と、初期化処理の高速化ができるようになっています。
$import
でテーブルを指定し、init()
で、$record
にデータを定義。
public $import = ['table' => 'content_folders'];
public function init(): void
{
$this->records = [
[
'id' => '1',
'folder_template' => 'baserCMSサンプル',
'page_template' => '',
'created' => '2016-08-10 02:17:28',
'modified' => null
]
];
$import
も init()
も定義せず、利用するかどうかを示すためだけに定義します。
全てを移行するには時間がかかるので、空のフィクスチャは、Factory
ディレクトリに入れるようにします。
// plugins/baser-core/tests/Fixture/Empty/UsersFixture
namespace BaserCore\Test\Fixture\Empty;
use Cake\TestSuite\Fixture\TestFixture;
/**
* Class UsersFixture
*/
class UsersFixture extends TestFixture {}
データを生成するためのクラスです。各エンティティごとに定義します。
複数のデータを一括で作成できるなどのメリットがあります。また、Faker を利用することで、ランダムな文字列などを当て込むことができます。
作りたいレコードの種類ごとにメソッドを用意する方針で利用していきます。
namespace BaserCore\Test\Factory;
use CakephpFixtureFactories\Factory\BaseFactory as CakephpBaseFactory;
use Faker\Generator;
class UserFactory extends CakephpBaseFactory
{
/**
* 管理ユーザーに設定する
* @return UserFactory
*/
public function admin()
{
return $this->setField('id', 1)
->setField('user_group_id', 1);
}
}
なお、フィクスチャファクトリは、コマンドで自動生成できます。
bin/cake bake fixture_factory -p BaserCore TableName
データを利用したいシチュエーション別にシナリオを用意することができます。
例えば、インストール直後の最低限のデータや、大量のブログ記事データなど。
// 最低限のメインサイトと管理ユーザーをだけを準備する
namespace BaserCore\Test\Scenario;
use BaserCore\Test\Factory\SiteFactory;
use BaserCore\Test\Factory\UserFactory;
use CakephpFixtureFactories\Scenario\FixtureScenarioInterface;
class InitAppScenario implements FixtureScenarioInterface
{
/**
* load
*/
public function load(...$args)
{
SiteFactory::make()->main()->persist();
UserFactory::make()->admin()->persist();
}
}
make()
メソッドで、データを作り、persist()
で永続化(DBへ保存)します。
// status が有効なユーザーを5名保存
UserFactory::make(['status' => true], 5)->persist();
// 無効ユーザーを100人追加
UserFactory::make(100)->suspended()->persist();
loadFixtureScenario
メソッドを利用して、クラスを読み込む事で実行します。
なお、ScenarioAwareTrait
の実装が必要です。
// シナリオを利用して無効ユーザーを50人追加
$this->loadFixtureScenario(SuspendedUsersScenario::class, 50);
// 最低限のメインサイトと管理ユーザーをだけを準備する
$this->loadFixtureScenario(InitAppScenario::class);
テストの実行後にデータの初期化を行うには、$fixtures
の定義が必要です。
$fixtures
に定義されているテーブルが初期化対象となるためです。
public $fixtures = [
'plugin.BaserCore.Factory/Users',
'plugin.BaserCore.Factory/Sites',
];
定義の仕方は従来と同じなのですが、この時に、フィクスチャファイルに、$record
の定義が入っていると混乱を生む原となってしまいます。
Factory
ディレクトリ内に定義した、空のフィクスチャファイルを利用するようにしましょう。
なお、初期化方法については、truncate(TruncateStrategy
) と DB のロールバック(TransactionStrategy
)があるのですが、ロールバックの方が高速であるため、初期状態ではこちらを設定しています。
ロールバック時の問題としては、インクリメント値が初期化されないため、テストにおいて初期化される事が前提となっている場合は、明示的にインクリメント値を初期化するか、TruncateStrategy
を利用するようにテストケースクラスに定義します。
// 親の setUp() の前に実行する
public function setUp(): void
{
$this->setFixtureTruncate();
parent::setUp();
}
また、TransactionStrategy
を利用している場合は、データベースに保存されているものの、
トランザクションとして commit されませんので、ブレークポイントでプログラムを止めて、
phpMyAdmin などのツールからデータの保存を確認するという事ができませんので注意が必要です。
確認したい場合は、setFixtureTruncate()
メソッドで、truncate に切り替えてからテストを実行してください。
DBトランザクションを利用しているメソッドのテストを行う場合に「SAVEPOINT LEVEL1 does not exist」というエラーが発生する事があります。
フィクスチャーにて、TransactionStrategy
を利用している事に起因する場合があり、その際、TruncateStrategy
に変更する事によってエラーを回避できます。
public function setUp(): void
{
$this->setFixtureTruncate(); // TruncateStrategy に変更、setUp() の前で定義する
parent::setUp();
}