イントロダクションIntroduction
Laravelでは、データベースを駆動するアプリケーションのテストを簡単にできる、便利で数多くのツールを用意しています。その一つは、指定した抽出条件に一致するデータがデータベース中に存在するかをアサートする、assertDatabaseHas
ヘルパです。たとえば、users
テーブルの中にemail
フィールドがsally@example.com
の値のレコードが存在するかを確認したいとしましょう。次のようにテストできます。Laravel provides a variety of helpful tools to make it easier to test your database driven applications. First, you may use the assertDatabaseHas
helper to assert that data exists in the database matching a given set of criteria. For example, if you would like to verify that there is a record in the users
table with the email
value of sally@example.com
, you can do the following:
public function testDatabase()
{
// アプリケーションを呼び出す…
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);
}
データベースにデータが存在しないことをアサートする、assertDatabaseMissing
ヘルパを使うこともできます。You can also use the assertDatabaseMissing
helper to assert that data does not exist in the database.
assertDatabaseHas
メソッドやその他のヘルパは、皆さんが便利に使ってもらうため用意しています。PHPUnitの組み込みアサートメソッドは、機能テストで自由に使用できます。The assertDatabaseHas
method and other helpers like it are for convenience. You are free to use any of PHPUnit's built-in assertion methods to supplement your feature tests.
ファクトリの生成Generating Factories
ファクトリを生成するには、make:factory
Artisanコマンドを使用します。To create a factory, use the make:factory
Artisan command[/docs/{{version}}/artisan]:
php artisan make:factory PostFactory
新しいファクトリは、database/factories
ディレクトリに設置されます。The new factory will be placed in your database/factories
directory.
--model
オプションにより、ファクトリが生成するモデルの名前を指定できます。このオプションは、生成するファクトリファイルへ指定モデル名を事前に設定します。The --model
option may be used to indicate the name of the model created by the factory. This option will pre-fill the generated factory file with the given model:
php artisan make:factory PostFactory --model=Post
各テスト後のデータベースリセットResetting The Database After Each Test
前のテストがその後のテストデータに影響しないように、各テストの後にデータベースをリセットできると便利です。インメモリデータベースを使っていても、トラディショナルなデータベースを使用していても、RefreshDatabase
トレイトにより、マイグレーションに最適なアプローチが取れます。テストクラスにてこのトレイトを使えば、すべてが処理されます。It is often useful to reset your database after each test so that data from a previous test does not interfere with subsequent tests. The RefreshDatabase
trait takes the most optimal approach to migrating your test database depending on if you are using an in-memory database or a traditional database. Use the trait on your test class and everything will be handled for you:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* 基本的な機能テストの例
*
* @return void
*/
public function testBasicExample()
{
$response = $this->get('/');
// …
}
}
ファクトリの記述Writing Factories
テスト実行前に、何件かのレコードをデータベースに挿入する必要があります。こうしたテストデータを作る時に、手動でそれぞれのカラムへ値を指定する代わりに、Laravelではモデルファクトリを使用し、Eloquentモデルの各属性にデフォルト値を設定できます。手始めに、アプリケーションのdatabase/factories/UserFactory.php
ファイルを見てください。このファイルには初めからファクトリの定義が一つ含まれています。When testing, you may need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Laravel allows you to define a default set of attributes for each of your Eloquent models[/docs/{{version}}/eloquent] using model factories. To get started, take a look at the database/factories/UserFactory.php
file in your application. Out of the box, this file contains one factory definition:
use Faker\Generator as Faker;
use Illuminate\Support\Str;
$factory->define(App\User::class, function (Faker $faker) {
return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
];
});
ファクトリで定義しているクロージャの中から、モデルの全属性に対するデフォルトのテスト値を返しています。このクロージャはFaker PHPライブラリーのインスタンスを受け取っており、これはテストのための多用なランダムデータを生成するのに便利です。Within the Closure, which serves as the factory definition, you may return the default test values of all attributes on the model. The Closure will receive an instance of the Faker[https://github.com/fzaninotto/Faker] PHP library, which allows you to conveniently generate various kinds of random data for testing.
より組織立てるために、各モデルごとに追加のファクトリファイルを作成することもできます。たとえば、database/factories
ディレクトリにUserFactory.php
とCommentFactory.php
ファイルを作成できます。factories
ディレクトリ下の全ファイルは、Laravelにより自動的にロードされます。You may also create additional factory files for each model for better organization. For example, you could create UserFactory.php
and CommentFactory.php
files within your database/factories
directory. All of the files within the factories
directory will automatically be loaded by Laravel.
">Tip!! Fakerのローケルは、
config/app.php
設定ファイルのfaker_locale
オプションで指定できます。{tip} You can set the Faker locale by adding afaker_locale
option to yourconfig/app.php
configuration file.
ファクトリの拡張Extending Factories
モデルを拡張する場合、テストやシーディングで子モデルのファクトリ属性を活用するため、ファクトリも同様に拡張すると便利です。これを実現するため、ファクトリビルダのraw
メソッドを呼び出し、指定したファクトリの属性配列をそのまま取得できます。If you have extended a model, you may wish to extend its factory as well in order to utilize the child model's factory attributes during testing and seeding. To accomplish this, you may call the factory builder's raw
method to obtain the raw array of attributes from any given factory:
$factory->define(App\Admin::class, function (Faker\Generator $faker) {
return factory(App\User::class)->raw([
// ...
]);
});
ファクトリステートFactory States
ステートにより、モデルファクトリのどんな組み合わせに対しても適用できる、個別の調整を定義できます。たとえば、User
モデルは、デフォルト属性値の一つを変更する、delinquent
ステートを持つとしましょう。state
メソッドを使い、状態変換を定義します。単純なステートでは、属性の変換の配列を渡します。States allow you to define discrete modifications that can be applied to your model factories in any combination. For example, your User
model might have a delinquent
state that modifies one of its default attribute values. You may define your state transformations using the state
method. For simple states, you may pass an array of attribute modifications:
$factory->state(App\User::class, 'delinquent', [
'account_status' => 'delinquent',
]);
ステートで計算や$faker
インスタンスが必要な場合は、ステートの属性変換を計算するために、クロージャを使います。If your state requires calculation or a $faker
instance, you may use a Closure to calculate the state's attribute modifications:
$factory->state(App\User::class, 'address', function ($faker) {
return [
'address' => $faker->address,
];
});
ファクトリコールバックFactory Callbacks
ファクトリコールバックはafterMaking
とafterCreating
メソッドを使用し登録し、モデルを作成、もしくは生成した後の追加タスクを実行できるようにします。例として、生成したモデルに追加のモデルを関係づけるコールバックを利用してみましょう。Factory callbacks are registered using the afterMaking
and afterCreating
methods, and allow you to perform additional tasks after making or creating a model. For example, you may use callbacks to relate additional models to the created model:
$factory->afterMaking(App\User::class, function ($user, $faker) {
// ...
});
$factory->afterCreating(App\User::class, function ($user, $faker) {
$user->accounts()->save(factory(App\Account::class)->make());
});
ファクトリステートのために、コールバックを定義することも可能です。You may also define callbacks for factory states[#factory-states]:
$factory->afterMakingState(App\User::class, 'delinquent', function ($user, $faker) {
// …
});
$factory->afterCreatingState(App\User::class, 'delinquent', function ($user, $faker) {
// …
});
ファクトリの使用Using Factories
モデルの生成Creating Models
ファクトリを定義し終えたら、機能テストかデータベースのシーディング(初期値設定)ファイルの中で、グローバルなfactory
関数を使用してモデルインスタンスを生成できます。では、モデル生成の例をいくつか見てみましょう。最初はmake
メソッドでモデルを生成し、データベースには保存しない方法です。Once you have defined your factories, you may use the global factory
function in your feature tests or seed files to generate model instances. So, let's take a look at a few examples of creating models. First, we'll use the make
method to create models but not save them to the database:
public function testDatabase()
{
$user = factory(App\User::class)->make();
// モデルをテストで使用…
}
さらにモデルのコレクションや指定したタイプのモデルも生成できます。You may also create a Collection of many models or create models of a given type:
// App\Userインスタンスを3つ生成
$users = factory(App\User::class, 'admin', 3)->make();
ステートの適用Applying States
こうしたモデルに対してステートを適用することもできます。複数の状態遷移を適用したい場合は、それぞれの適用対象のステート名を指定します。You may also apply any of your states[#factory-states] to the models. If you would like to apply multiple state transformations to the models, you should specify the name of each state you would like to apply:
$users = factory(App\User::class, 5)->states('delinquent')->make();
$users = factory(App\User::class, 5)->states('premium', 'delinquent')->make();
属性のオーバーライドOverriding Attributes
モデルのデフォルト値をオーバーライドしたい場合は、make
メソッドに配列で値を渡してください。指定した値のみ置き換わり、残りの値はファクトリで指定したデフォルト値のまま残ります。If you would like to override some of the default values of your models, you may pass an array of values to the make
method. Only the specified values will be replaced while the rest of the values remain set to their default values as specified by the factory:
$user = factory(App\User::class)->make([
'name' => 'Abigail',
]);
複数代入の保護を自動的に無効にします。{tip} Mass assignment protection[/docs/{{version}}/eloquent#mass-assignment] is automatically disabled when creating models using factories.
">Tip!! ファクトリを用いモデルを生成する場合は、
モデルの保存Persisting Models
create
メソッドはモデルインスタンスを生成するだけでなく、Eloquentのsave
メソッドを使用しデータベースへ保存します。The create
method not only creates the model instances but also saves them to the database using Eloquent's save
method:
public function testDatabase()
{
// 一つのApp\Userインスタンスを作成
$user = factory(App\User::class)->create();
// App\Userインスタンスを3つ生成
$users = factory(App\User::class, 3)->create();
// モデルをテストで使用…
}
create
メソッドに配列で値を渡すことで、モデルの属性をオーバーライドできます。You may override attributes on the model by passing an array to the create
method:
$user = factory(App\User::class)->create([
'name' => 'Abigail',
]);
リレーションRelationships
以下の例では、生成したモデルにリレーションを付けています。複数モデルの生成にcreate
メソッドを使用する場合、インスタンスのコレクションが返されます。そのため、コレクションで使用できるeach
などの便利な関数が利用できます。In this example, we'll attach a relation to some created models. When using the create
method to create multiple models, an Eloquent collection instance[/docs/{{version}}/eloquent-collections] is returned, allowing you to use any of the convenient functions provided by the collection, such as each
:
$users = factory(App\User::class, 3)
->create()
->each(function ($user) {
$user->posts()->save(factory(App\Post::class)->make());
});
関係を複数持つモデルを生成する場合は、createMany
メソッドを使用します。You may use the createMany
method to create multiple related models:
$user->posts()->createMany(
factory(App\Post::class, 3)->make()->toArray()
);
リレーションと属性クロージャRelations & Attribute Closures
ファクトリ定義の中でモデルとのリレーションを指定することもできます。たとえば、Post
を作成する時に、新しいUser
インスタンスも作成したい場合は、以下のようになります。You may also attach relationships to models in your factory definitions. For example, if you would like to create a new User
instance when creating a Post
, you may do the following:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => factory(App\User::class),
];
});
リレーションが定義するファクトリに依存する場合は、評価済みの属性配列を引数に取るコールバックを指定してください。If the relationship depends on the factory that defines it you may provide a callback which accepts the evaluated attribute array:
$factory->define(App\Post::class, function ($faker) {
return [
'title' => $faker->title,
'content' => $faker->paragraph,
'user_id' => factory(App\User::class),
'user_type' => function (array $post) {
return App\User::find($post['user_id'])->type;
},
];
});
シーダの使用Using Seeds
機能テストでデータベースへ初期値を設定するために、データベースシーダを使いたい場合は、seed
メソッドを使用してください。デフォルトでseed
メソッドは、他のシーダを全部実行するDatabaseSeeder
を返します。もしくは、seed
メソッドへ特定のシーダクラス名を渡してください。If you would like to use database seeders[/docs/{{version}}/seeding] to populate your database during a feature test, you may use the seed
method. By default, the seed
method will return the DatabaseSeeder
, which should execute all of your other seeders. Alternatively, you pass a specific seeder class name to the seed
method:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use OrderStatusesTableSeeder;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* Test creating a new order.
*
* @return void
*/
public function testCreatingANewOrder()
{
// DatabaseSeederを実行
$this->seed();
// シーダを1つ実行
$this->seed(OrderStatusesTableSeeder::class);
// ...
}
}
使用可能なアサーションAvailable Assertions
Laravelは、多くのデータベースアサーションをPHPUnit機能テスト向けに提供しています。Laravel provides several database assertions for your PHPUnit[https://phpunit.de/] feature tests:
メソッドMethod | 説明Description |
---|---|
$this->assertDatabaseHas($table, array $data); $this->assertDatabaseHas($table, array $data); |
指定したデータが、テーブルに存在することをアサートAssert that a table in the database contains the given data. |
$this->assertDatabaseMissing($table, array $data); $this->assertDatabaseMissing($table, array $data); |
指定したデータが、テーブルに含まれないことをアサートAssert that a table in the database does not contain the given data. |
$this->assertDeleted($table, array $data); $this->assertDeleted($table, array $data); |
指定したレコードが削除されていることをアサートAssert that the given record has been deleted. |
$this->assertSoftDeleted($table, array $data); $this->assertSoftDeleted($table, array $data); |
指定したレコードがソフトデリートされていることをアサートAssert that the given record has been soft deleted. |
レコードの削除・ソフト削除のアサートに便利なよう、assertDeleted
とassertSoftDeleted
ヘルパへはモデルが渡せるようになっています。その場合、モデルの主キーを利用します。For convenience, you may pass a model to the assertDeleted
and assertSoftDeleted
helpers to assert the record was deleted or soft deleted, respectively, from the database based on the model's primary key.
たとえば、モデルファクトリをテストで使用する場合に、アプリケーションでデータベースからそのレコードが確実に削除されているかをテストするために、これらのヘルパへモデルを渡せます。For example, if you are using a model factory in your test, you may pass this model to one of these helpers to test your application properly deleted the record from the database:
public function testDatabase()
{
$user = factory(App\User::class)->create();
// アプリケーションで操作する
$this->assertDeleted($user);
}