CakePHP4のFixture Factoriesプラグインの使い方
はじめに
CakePHP標準のDBのテストは共通のFixtureまたは単位に合わせたFixtureファイルを作成して行います。
大規模になってくるとFixtureファイルが各テストごと作成されたり共有データを意識すると状態管理が難しくなってきます。
それを解決するのが CakePHP Fixture Factories Pluginになります。
このプラグインでは、テストのメッソッドに応じて動的にFixtureを登録できるため管理しやすくなります。
検証環境
- PHP 7.4
- CakePHP4.4.12
- CakePHP Fixture Factories v2.7.1
セットアップ
プラグインのインストール
composer require --dev vierge-noire/cakephp-fixture-factories "^2.5"
プラグインをロードする
protected function bootstrapCli(): void
{
// Load more plugins here
if (Configure::read('debug')) {
$this->addPlugin('CakephpFixtureFactories');
}
}
使い方
FixtureFactoryクラスを作成する
bakeコマンドが用意されているので以下のコマンドにより生成します。
bin/cake bake fixture_factory -a
FixtureFactoryはBaseFactoryを継承して利用します。
最低実装しなければならないのは以下の2つのメソッドです。
-
getRootTableRegistryName()
Factoryで利用するTable名を示します。 -
setDefaultTemplate()
Factory::make()で生成するデフォルトデータを記述します。
class ArticleFactory extends BaseFactory
{
protected function getRootTableRegistryName(): string
{
return 'Articles';
}
protected function setDefaultTemplate(): void
{
$this->setDefaultData(function (Generator $faker) {
return [
'name' => $faker->lastName
];
});
}
}
テストデータの作成する
CakePHP4.3からFixtureの機能に大きく変更が入りFixtureの戦略を変更することができます。
TruncateDirtyTables
というトレイトが用意されていのでこれを利用いします。
これを設定しない場合、FixtureFactoryで生成されたデータが各テストケース終了時にドロップされません。
public function ArticlesTest extends TestCase
{
use TruncateDirtyTables;
}
データ利用方法には2パターンあり永続化しないパターンと永続化するパターンになります。
永続化しないパターンは永続化前のロジックのテストに最適です。
永続化するパターンはfinderなどのすでに永続化されたものを対象とするテストに用います。
永続化しないパターン
1件のデータを生成する場合は以下のように記述します。
$article = ArticleFactory::make()->getEntity();
$article = ArticleFactory::make(['title' => 'hoge'])->getEntity();
複数生成する場合は以下のように記述します。
$articles = ArticleFactory::make(3)->getEntities();
$articles = ArticleFactory::make(['title' => 'hoge'], 3)->getEntities();
永続化するパターン
1件のデータを生成する場合はgetEntity()
の代わりにpersist()
呼び出し以下のように記述します。
$article = ArticleFactory::make()->persist();
$article = ArticleFactory::make(['title' => 'hoge'])->persist();
$articles = ArticleFactory::make(3)->persit();
$articles = ArticleFactory::make(['title' => 'hoge'], 3)->persit();
関係モデルのデータを作成する
ルートモデルの関係モデルを同時に生成することも可能です。
関連モデルの生成はwith()
メソッドを用います。
ArticleFactory::make(1)->with('Authors', AutherFactory::make(2))->persist()
ArticleFactoryに関連モデルの定義を行っている場合、以下のように書くこともできます。
class ArticleFactory extends BaseFactory
{
public function withAuthors($parameter = null, int $n = 1): self
{
return $this->with('Authors', AuthorFactory::make($parameter, $n));
}
}
ArticleFactory::make(1)->withAuthors(10)->persist()
再利用可能なデータセットを利用する
標準のFixtureのようにデータを共有して再利用して使いたいということもあるかと思います。
その場合は シナリオ(Scenario) という機能が有効です。
シナリオはApp\Test\Scenario
に配置します。
シナリオクラスはFixtureScenarioInterface
を適合しload()
メソッドを実装します。
例を以下に示します。
class AllStatusArticlesScenario implments FixtureScenarioInterface
{
public function load($n = 1, ...$args)
{
return ArticleFactory::make([['status' => 'draft'], ['status' => 'publish']], $n);
}
}
テストでシナリオを利用するにはScenarioAwareTrait
よりloadFxtureScenario()
を呼び出して利用します。
これはステータスのシナリオから公開ステータスのみ抽出するfindPublishedメソッドのテスト例です。
class ArticlesTableTest extends TestCase
{
use ScenarioAwareTrait;
public function testFindPublished()
{
$this->loadFixtureScenario(AllStatusArticlesScenario::class, 1)->persist();
$articles = $this->Articles->find('published')->all();
$this->assertSame(1, $articles->count());
foreach ($articles as $article) {
$this->assertSame('publish', $article->status)
}
}
}
最後に
いかがだったでしょうか?
今回はFixture Factoriesプラグインの使い方に関して書いてみました。
CakePHP4のFixtureが辛いというかたは試して見ではどうでしょうか。
Discussion