テストデータの生成

アプリケーションでテストを実行するには、多くの場合、サンプルデータが必要です。 Fabricator クラスは、fzaninottoの Faker を使用して、モデルをランダムデータのジェネレーターに変換します。ユニットテストのために偽のデータを準備するには、シードまたはテストケースでファブリケーターを使用します。

サポートされているモデル

Fabricator は、フレームワークのコアモデルである CodeIgniter\Model を拡張するすべてのモデルをサポートします。 CodeIgniter\Test\Interfaces\FabricatorModel を実装することで、独自のカスタムモデルを使用できます。

<?php

namespace App\Models;

use CodeIgniter\Test\Interfaces\FabricatorModel;

class MyModel implements FabricatorModel
{
    // ...
}

注記

メソッドに加えて、インターフェースはターゲットモデルに必要ないくつかのプロパティを概説しています。詳細はインターフェースコードを参照してください。

ファブリケーターの読み込み

最も基本的なファブリケーターは、操作対象のモデルを受け取ります。

<?php

use App\Models\UserModel;
use CodeIgniter\Test\Fabricator;

$fabricator = new Fabricator(UserModel::class);

パラメーターには、モデル名を指定する文字列、またはモデル自体のインスタンスを指定できます。

<?php

use App\Models\UserModel;
use CodeIgniter\Test\Fabricator;

$model = new UserModel($testDbConnection);

$fabricator = new Fabricator($model);

フォーマッターの定義

Fakerは、フォーマッターからリクエストすることでデータを生成します。フォーマッターが定義されていない場合、Fabricator は、フィールド名とそれが表すモデルのプロパティに基づいて、最も適切な適合を推測しようとします($fabricator->defaultFormatter にフォールバックします)。フィールド名が一般的なフォーマッターに対応している場合、またはフィールドの内容をあまり気にしない場合はこれで問題ないかもしれませんが、ほとんどの場合、コンストラクターの2番目のパラメーターとして使用するフォーマッターを指定する必要があります。

<?php

use App\Models\UserModel;
use CodeIgniter\Test\Fabricator;

$formatters = [
    'first'  => 'firstName',
    'email'  => 'email',
    'phone'  => 'phoneNumber',
    'avatar' => 'imageUrl',
];

$fabricator = new Fabricator(UserModel::class, $formatters);

setFormatters() メソッドを使用して、ファブリケーターの初期化後にフォーマッターを変更することもできます。

高度なフォーマット

場合によっては、フォーマッターのデフォルトの戻り値では不十分な場合があります。Fakerプロバイダーは、ほとんどのフォーマッターにパラメーターを許可し、ランダムデータの範囲をさらに制限します。ファブリケーターは、偽のデータがどのようなものになるかを正確に定義できる fake() メソッドについて、その代表的なモデルをチェックします。

<?php

namespace App\Models;

class UserModel
{
    // ...

    public function fake(Generator &$faker)
    {
        return [
            'first'  => $faker->firstName,
            'email'  => $faker->email,
            'phone'  => $faker->phoneNumber,
            'avatar' => Faker\Provider\Image::imageUrl(800, 400),
            'login'  => config('Auth')->allowRemembering ? date('Y-m-d') : null,
        ];

        /*
         * Or you can return a return type object.

        return new User([
            'first'  => $faker->firstName,
            'email'  => $faker->email,
            'phone'  => $faker->phoneNumber,
            'avatar' => Faker\Provider\Image::imageUrl(800, 400),
            'login'  => config('Auth')->allowRemembering ? date('Y-m-d') : null,
        ]);

        */
    }
}

この例では、最初の3つの値が以前のフォーマッターと同等であることに注意してください。ただし、avatar の場合は、デフォルト以外の画像サイズを要求し、login はアプリの設定に基づいた条件を使用しています。どちらも $formatters パラメーターでは不可能です。テストデータを本番モデルとは別に保持することをお勧めするため、テストサポートフォルダに子クラスを定義することをお勧めします。

<?php

namespace Tests\Support\Models;

use App\Models\UserModel;

class UserFabricator extends UserModel
{
    public function fake(&$faker)
    {
        // ...
    }
}

ローカリゼーション

Fakerは多くの異なるロケールをサポートしています。使用するロケールがどのプロバイダーをサポートしているかについては、そのドキュメントを確認してください。ファブリケーターを初期化するときに、3番目のパラメーターでロケールを指定します。

<?php

use App\Models\UserModel;
use CodeIgniter\Test\Fabricator;

$fabricator = new Fabricator(UserModel::class, null, 'fr_FR');

ロケールが指定されていない場合、app/Config/App.phpdefaultLocale として定義されているロケールが使用されます。既存のファブリケーターのロケールは、その getLocale() メソッドを使用して確認できます。

データの偽装

適切に初期化されたファブリケーターがあれば、make() コマンドでテストデータを簡単に生成できます。

<?php

use CodeIgniter\Test\Fabricator;

$fabricator = new Fabricator(\UserFabricator::class);
$testUser   = $fabricator->make();
print_r($testUser);

次のようなものが返される可能性があります。

<?php

[
    'first'  => 'Maynard',
    'email'  => '[email protected]',
    'phone'  => '201-886-0269 x3767',
    'avatar' => 'http://lorempixel.com/800/400/',
    'login'  => null,
];

カウントを指定することで、大量のデータを取得することもできます。

<?php

$users = $fabricator->make(10);

make() の戻り値の型は、代表的なモデルで定義されているものを模倣していますが、メソッドを直接使用して型を強制することもできます。

<?php

$userArray  = $fabricator->makeArray();
$userObject = $fabricator->makeObject();
$userEntity = $fabricator->makeObject('App\Entities\User');

make() からの戻り値は、テストで使用したり、データベースに挿入したりする準備ができています。あるいは、Fabricator には create() コマンドが含まれており、これを使用してデータを挿入し、結果を返すことができます。モデルのコールバック、データベースのフォーマット、プライマリキーやタイムスタンプなどの特別なキーのため、create() からの戻り値は make() と異なる場合があります。次のようなものが返される可能性があります。

<?php

[
    'id'         => 1,
    'first'      => 'Rachel',
    'email'      => '[email protected]',
    'phone'      => '741-241-2356',
    'avatar'     => 'http://lorempixel.com/800/400/',
    'login'      => null,
    'created_at' => '2020-05-08 14:52:10',
    'updated_at' => '2020-05-08 14:52:10',
];

make() と同様に、カウントを指定してオブジェクトの配列を挿入して返すことができます。

<?php

$users = $fabricator->create(100);

最後に、完全なデータベースオブジェクトでテストしたいが、実際にはデータベースを使用していない場合があるかもしれません。create() は、オブジェクトのモックを許可する2番目のパラメーターを受け取り、実際にはデータベースに触れることなく、上記の追加のデータベースフィールドを含むオブジェクトを返します。

<?php

$user = $fabricator(null, true);

$this->assertIsNumeric($user->id);
$this->dontSeeInDatabase('user', ['id' => $user->id]);

テストデータの指定

生成されたデータは素晴らしいですが、フォーマッターの設定を損なうことなく、テストに特定のフィールドを指定したい場合があります。各バリアントごとに新しいファブリケーターを作成するのではなく、setOverrides() を使用して、任意のフィールドの値を指定できます。

<?php

$fabricator->setOverrides(['first' => 'Bobby']);
$bobbyUser = $fabricator->make();

これで、make() または create() で生成されたデータは、常に first フィールドに「Bobby」を使用します。

<?php

[
    'first'  => 'Bobby',
    'email'  => '[email protected]',
    'phone'  => '251-806-2169',
    'avatar' => 'http://lorempixel.com/800/400/',
    'login'  => null,
];

[
    'first'  => 'Bobby',
    'email'  => '[email protected]',
    'phone'  => '525-214-2656 x23546',
    'avatar' => 'http://lorempixel.com/800/400/',
    'login'  => null,
];

setOverrides() は、これが永続的なオーバーライドであるか、単一のアクションのためだけであるかを示す2番目のパラメーターを取ることができます。

<?php

$fabricator->setOverrides(['first' => 'Bobby'], $persist = false);
$bobbyUser = $fabricator->make();
$bobbyUser = $fabricator->make();

最初の戻り値の後、ファブリケーターはオーバーライドを使用しなくなります。

<?php

[
    'first'  => 'Bobby',
    'email'  => '[email protected]',
    'phone'  => '741-857-1933 x1351',
    'avatar' => 'http://lorempixel.com/800/400/',
    'login'  => null,
];

[
    'first'  => 'Hans',
    'email'  => '[email protected]',
    'phone'  => '487-235-7006',
    'avatar' => 'http://lorempixel.com/800/400/',
    'login'  => null,
];

2番目のパラメーターが指定されていない場合、渡された値はデフォルトで永続化されます。

テストヘルパー

多くの場合、テストに必要なのは使い捨ての偽オブジェクトだけです。テストヘルパーは、まさにこれを行う fake($model, $overrides, $persist = true) 関数を提供します。

<?php

helper('test');
$user = fake('App\Models\UserModel', ['name' => 'Gerry']);

これは次のと同等です。

<?php

use CodeIgniter\Test\Fabricator;

$fabricator = new Fabricator('App\Models\UserModel');
$fabricator->setOverrides(['name' => 'Gerry']);
$user = $fabricator->create();

データベースに保存せずに偽のオブジェクトだけが必要な場合は、persistパラメーターにfalseを渡すことができます。

テーブルカウント

多くの場合、偽データは他の偽データに依存します。Fabricator は、各テーブルに対して作成された偽アイテムの数を静的なカウントで提供します。以下の例を考えてみましょう。

プロジェクトにユーザーとグループがあるとします。テストケースで様々なサイズのグループを持つシナリオを作成したい場合、Fabricator を使用して多数のグループを作成します。次に、偽のユーザーを作成しますが、存在しないグループIDに割り当てることは避けたいとします。モデルの偽メソッドは次のようになります。

<?php

namespace App\Models;

class UserModel
{
    protected $table = 'users';

    public function fake(Generator &$faker)
    {
        return [
            'first'    => $faker->firstName,
            'email'    => $faker->email,
            'group_id' => mt_rand(1, Fabricator::getCount('groups')),
        ];
    }
}

これで、新しいユーザーを作成すると、有効なグループの一部になることが保証されます。$user = fake(UserModel::class);

メソッド

Fabricator は内部的にカウントを処理しますが、これらの静的メソッドにアクセスして使用することもできます。

getCount(string $table): int

特定のテーブルの現在の値を返します(デフォルト:0)。

setCount(string $table, int $count): int

特定のテーブルの値を手動で設定します。例えば、ファブリケーターを使用せずにいくつかのテストアイテムを作成した場合でも、最終的なカウントに反映させたい場合などです。

upCount(string $table): int

特定のテーブルの値を1つ増やし、新しい値を返します。(これはFabricator::create()内部で使用されている方法です)。

downCount(string $table): int

特定のテーブルの値を1つ減らし、新しい値を返します。例えば、偽のアイテムを削除した場合でも、その変更を追跡したい場合などです。

resetCounts()

すべてのカウントをリセットします。テストケース間でこれを呼び出すことをお勧めします(ただし、CIUnitTestCase::$refresh = trueを使用すると自動的に実行されます)。