Help us understand the problem. What is going on with this article?

Fakerで自動テスト用のダミーデータ作成を自動化する

More than 5 years have passed since last update.

データベースを含んだ自動テストは面倒ですね。なにが面倒って、テスト用のデータ、いわゆるフィクスチャを準備するのがもう。

Yii はデータベースの結果をモックする純粋なロジックテストではなく、ファンクショナルテストやデータベース込みのテストを指向しています。2.0 になって、BDDふうのテスティングフレームワーク Codeception のテストプロジェクトが一式ついてくるようになりました。BDD ふうにページをテストするにはホンモノが動くことが前提、つまりデータベースも当然要るわけです。

フィクスチャはすべて手書きしてもいいのですが、たとえば 21 件以上でページネーションすることを試そうと思ったら...

というわけで Faker を活用しましょう。

Yii のプロジェクトテンプレートの tests フォルダ以下には、テスト環境専用の codeception\bin\yii コマンドが置いてあり、こんな感じで、フィクスチャのサポートが追加で組み込まれています。

$config = yii\helpers\ArrayHelper::merge(
    // ... ,
    [
        'controllerMap' => [
            'fixture' => [
                'class' => 'yii\faker\FixtureController',
                'fixtureDataPath' => '@tests/codeception/fixtures/data',
                'templatePath' => '@tests/codeception/templates',
                'namespace' => 'tests\codeception\fixtures',
            ],
        ],
    ]
);

設定にしたがって tests/codeception/templates にフィクスチャのテンプレートを書きます。たとえばユーザー用のフィクスチャなら templates/user.php にこう書きます。

<?php
/**
 * @var $faker \Faker\Generator
 * @var $index integer
 */
return [
    'email' => $faker->email,
    'password_hash' => Yii::$app->security->generatePasswordHash('password_' . $index),
    'auth_key' => Yii::$app->security->generateRandomString(),
    'name' => $faker->firstName . ' ' . $faker->lastName,
    'birthday' => $faker->date(),
    'created_at' => $faker->unixTime,
    'updated_at' => $faker->unixTime,
];

$faker からプロパティを取ると、取り出すたびにデタラメなそれらしいデータが出てきます。ランダムだと困るものは、 $index を使うと計算で出したり決まった配列から取り出したりできます。

で、 tests/codeception/bin/yii fixture/generate user を実行するとテンプレートのパスとデータのパスが設定してあるので...

$ tests/codeception/bin/yii fixture/generate user
Fixtures will be generated under the path: 
        /.../tests/codeception/fixtures/data

Templates will be taken from path: 
        /.../tests/codeception/templates

        * user
Generate above fixtures? (yes|no) [no]: yes
The following fixtures template files were generated:

        * user

はい、これでできました。じゃーん!

<?php

return [
    [
        'email' => 'pauline22@weber.info',
        'password_hash' => '$2y$13$kU/MfgI/XUD6JacW7VFe2O3iab3pksTEvrXaJ9c0mof86lnNEJwW.',
        'auth_key' => 'l7iv336Q00OrP0Mcn7sUgvbUAhd3gU1W',
        'name' => 'Ophelia Jacobs',
        'birthday' => '1980-09-09',
        'created_at' => 602074437,
        'updated_at' => 390537715,
    ],
    [
        'email' => 'kacie78@yahoo.com',
        'password_hash' => '$2y$13$ry7b0lKIcY1grUQmQBkjgupbRsNxAnoOsAgOwJsxgXQCnlljYM3W6',
        'auth_key' => 'Ux5iYaPTpY5pgym9fuwEjrZXOCdZbXO5',
        'name' => 'Audra Cole',
        'birthday' => '2010-05-17',
        'created_at' => 447193310,
        'updated_at' => 293260057,
    ],
];

2個じゃ足りないなら、

tests/codeception/bin/yii fixture/generate user --count=10

で、こういうのが 10 件でも 20 件でも作れます。

本当にバラバラなデータを手で作るのは面倒だし、人間が手でやるとどうしても恣意的になってしまいます。思い込みでテストケースの漏れが出てくることもあります。

テンプレートから生成することのメリットとして、再現性のないパスワードハッシュを固定できるというのもあります。フィクスチャデータで generatePasswordHash を呼ぶと、セキュリティの都合で実際には毎回違うデータになってしまいます。細かいことかもしれませんが、フィクスチャデータで値を生成すると、場合によっては失敗を再現できないかもしれません。フィクスチャデータはテストコードの一部です。

というわけで、テンプレートがあるからといって、フィクスチャデータをバージョン管理しないというのはナシです。テストがグリーンでコミットしたことを確実に示すために、フィクスチャはバージョン管理しましょう。

バージョン管理するということは、もうこのデータは開発者のものです。生成し直すまで、好きなように編集して、都合の悪いところは適当に書き換えましょう。多対多テーブルなんかは、テンプレートを書かずにフィクスチャを直接書いてもいいかもしれません。

フィクスチャデータを使うには、クラスを定義しなければなりません。といっても、AssetBundle 並みに非常に簡単な実装です。テスト用 yii
コマンドの FixtureControllernamespace が指すところに...

<?php
namespace tests\codeception\fixtures;

use yii\test\ActiveFixture;

class UserFixture extends ActiveFixture
{
    public $modelClass = 'app\models\User';
    public $depends = [];
} 

$modelClass はどのテーブルにロードするかという情報を引くための ActiveRecord クラスです。

$depends には、このフィクスチャをロードする前にロードして欲しい他のフィクスチャのクラス名を複数登録します。まさに AssetBundle のノリですね。これで、ロード時に外部キーの先がないなんてこともありません。

これでデータをロードすることができるようになりました。自動テストを実行する前に、作ったデータが実際にデータベース入るかどうかを確認しておきます。テスト用のデータベースをマイグレーションして、そこにすべてのフィクスチャを流し込みます。

tests/codeception/bin/yii migrate/up
tests/codeception/bin/yii fixture/load "*"

成功したらOKです。外部キー制約や文字数制限などの都合で入らないフィクスチャを作っていると、テストでも使うことができません。確認し終わったらアンロードします。

tests/codeception/bin/yii fixture/unload "*"

さて、ここまでやってもらえればもうあとはモチベーションを下げるヤツはいません。自動テストをサクサク書いていきましょう。

時間もないので、各種のテストでどうやってロードするかは、マニュアルを参照したり、アプリケーションテンプレートから読み取ったりしてください。

なお、Faker は一般的な道具なので、Laravel でも Symfony でも使えます。Packagist には CakePHP3 のプラグインも見かけました。

Laravel で Faker を使う場合は Jeff の記事を参照して下さい。

http://codebyjeff.com/blog/2013/09/quick-tip-faker-and-laravel-seed-generators

メリー・クリスマス

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした