Factory,Fakerでテストデータ生成

Tag:

FactoryとFakerを利用して、モデルデータを生成してみます。テストやSeederでモデルデータを利用したいときに便利です。

Fakerでダミーデータ生成

まずは、Fakerを利用します。Fakerはデフォルトでcomposer.jsonに指定されており、ダミーデータを生成するために利用します。

動作確認

実際にFakerを利用してみます。Laravelのルーティングファイルに以下処理を記述します。

Route::get('/', function () {
    $faker = Faker\Factory::create('ja_JP');
    $dummyData = [
        'name' => $faker->name,
        'password' => $faker->password,
        'country' => $faker->country,
        'prefecture' => $faker->prefecture,
        'city' => $faker->city,
        'postcode' => $faker->postcode,
        'address' => $faker->address,
        'streetAddress' => $faker->streetAddress,
        'phoneNumber' => $faker->phoneNumber,
        'email' => $faker->email,
        'safeEmail' => $faker->safeEmail,   // (実在しないアドレスのため処理とかで使っても安心)
        'company' => $faker->company,
        'iso8601' => $faker->iso8601($max = 'now'),
        'dateTimeBetween' => $faker->dateTimeBetween($startDate = '-110 years', $endDate = 'now')->format('Y年m月d日'),
        'numberBetween' => $faker->numberBetween($min = 100, $max = 200),
        'title' => $faker->title,
        'realText' => $faker->realText($maxNbChars = 50, $indexSize = 2),
        'randomNumber' => $faker->randomNumber($nbDigits = NULL),
        'randomFloat' => $faker->randomFloat($nbMaxDecimals = NULL, $min = 0, $max = NULL),
        'randomElement' => $faker->randomElement($array = ['男性', '女性']),
        'lexify' => $faker->lexify($string = '??????'),
        'hexcolor' => $faker->hexcolor,
        'ipv4' => $faker->ipv4,
        'url' => $faker->url,
        'imageUrl' => $faker->imageUrl($width = 640, $height = 480, $category = 'cats', $randomize = true, $word = null),
        'userAgent' => $faker->userAgent,
        'creditCardType' => $faker->creditCardType,
        'creditCardNumber' => $faker->creditCardNumber,
        'creditCardExpirationDate' => $faker->creditCardExpirationDate,
        'isbn13' => $faker->isbn13,
        'isbn10' => $faker->isbn10
    ];
    var_dump($dummyData);
    exit();
});

ブラウザで「/」にアクセスすると以下のように出力されているのを確認できました。

array (size=31)
  'name' => string '坂本 陽子' (length=13)
  'password' => string 'RVz\NfP(u!' (length=10)
  'country' => string 'ネパール' (length=12)
  'prefecture' => string '北海道' (length=9)
  'city' => string '村山市' (length=9)
  'postcode' => string '1629924' (length=7)
  'address' => string '4741212  熊本県小林市北区大垣町近藤3-6-6' (length=53)
  'streetAddress' => string '喜嶋町加納1-1-1' (length=20)
  'phoneNumber' => string '090-2258-2074' (length=13)
  'email' => string 'akira25@mail.goo.ne.jp' (length=22)
  'safeEmail' => string 'taro.nagisa@example.org' (length=23)
  'company' => string '株式会社 坂本' (length=19)
  'iso8601' => string '1999-10-12T15:45:56+0000' (length=24)
  'dateTimeBetween' => string '1927年10月23日' (length=17)
  'numberBetween' => int 154
  'title' => string 'Dr.' (length=3)
  'realText' => string 'かたむのをこさえ行けるのでした。すると、野原かわも、さっきりんごはんぶんなにかくにあるんです。ジョ。' (length=150)
  'randomNumber' => int 847374
  'randomFloat' => float 323067771.3062
  'randomElement' => string '女性' (length=6)
  'lexify' => string 'jhgnwp' (length=6)
  'hexcolor' => string '#8c3484' (length=7)
  'ipv4' => string '174.72.72.218' (length=13)
  'url' => string 'http://kudo.jp/error-ut-voluptatem-ad-libero-assumenda-et-autem' (length=63)
  'imageUrl' => string 'http://lorempixel.com/640/480/cats/?52441' (length=41)
  'userAgent' => string 'Mozilla/5.0 (Windows; U; Windows NT 6.0) AppleWebKit/533.6.5 (KHTML, like Gecko) Version/5.0.2 Safari/533.6.5' (length=109)
  'creditCardType' => string 'Visa' (length=4)
  'creditCardNumber' => string '5192313243195611' (length=16)
  'creditCardExpirationDate' => 
    object(DateTime)[259]
      public 'date' => string '2018-11-29 18:18:35.000000' (length=26)
      public 'timezone_type' => int 3
      public 'timezone' => string 'UTC' (length=3)
  'isbn13' => string '9797217934389' (length=13)
  'isbn10' => string '7918352467' (length=10)

Fakerの詳しい使い方などは、以下で確認できます。
https://github.com/fzaninotto/Faker

realTextを使う際の注意

realTextを使うと以下のエラーが出力されました。

ErrorException in Text.php line 623:
mb_substr() expects parameter 3 to be integer, string given

https://github.com/fzaninotto/Faker/issues/1003で取り上げられてますが、v1.6.0では以下の修正が必要です。(masterは修正済みなので、v1.7.0がリリースされれば大丈夫かと)

/vendor/fzaninotto/faker/src/Faker/Provider/ja_JP/Text.php
-            $last = mb_substr($text, mb_strlen($text)-1, 'UTF-8');
+            $last = mb_substr($text, mb_strlen($text)-1, null, 'UTF-8');

ファクトリーでモデルデータ生成

次にファクトリーを利用してみます。

前準備

まず動作確認用に準備を行います。ここでは、「usersテーブル」と「countriesテーブル」を作成して動作確認します。

マイグレーションファイル作成
class EloquentTest extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('countries', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });

        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->unsignedInteger('country_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('users');
        Schema::drop('countries');
    }
}

マイグレーション実行。

php artisan migrate
モデル作成
php artisan make:model User
php artisan make:model Country
Seeder作成
php artisan make:seeder  SeederCountriesTable
php artisan make:seeder  SeederUsersTable
FakerGeneratorが生成するインスタンスのlocaleをjpにする
「App\Providers\AppServiceProvider」に追記します。

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Faker\Generator as FakerGenerator;    // 追記
use Faker\Factory as FakerFactory;        // 追記

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        // 追記
        $this->app->singleton(FakerGenerator::class, function () {
            return FakerFactory::create('ja_JP');
        });
    }
}

ファクトリーモデルを定義

「database/factories/ModelFactory.php」でファクトリーモデルの定義を行います。

$factory->define(App\Country::class, function (Faker\Generator $faker) {
    return [
        'name' => $faker->country,
    ];
});

$factory->define(App\User::class, function (Faker\Generator $faker) {
    $countries = App\Country::pluck('id')->all();
    return [
        'name' => $faker->name,
        'country_id' => $faker->randomElement($countries),
    ];
});

Seederでファクトリーモデルを利用

Seederでファクトリーモデルを利用してみます。

class SeederCountriesTable extends Seeder
{
    public function run()
    {
        factory(App\Country::class, 10)->create();
    }
}
class SeederUsersTable extends Seeder
{
    public function run()
    {
        factory(App\User::class, 3)->create();
    }
}
class DatabaseSeeder extends Seeder
{
    public function run()
    {
        $this->call(SeederCountriesTable::class);
        $this->call(SeederUsersTable::class);
    }
}

Seeder実行

php artisan db:seed

「usersテーブル」と「countriesテーブル」にデータが挿入されていることを確認できました。

ファクトリーの使用例

// モデル生成のみ。データベースには保存しない。
$user = factory(App\User::class)->make();
 
// モデル生成して、データベースにも保存する。
$user = factory(App\User::class)->create();
 
// name属性をオーバーライド。他の属性は定義された通り。
$user = factory(App\User::class)->make([
    'name' => 'James',
]);

参考

https://readouble.com/laravel/5.4/ja/database-testing.html#writing-factories

スポンサーリンク