イントロダクションIntroduction
Laravelアプリケーションをテストするとき、アプリケーションの一部分を「モック」し、特定のテストを行う間は実際のコードを実行したくない場合があります。たとえば、イベントを発行するコントローラをテストする時は、実際に実行したくないイベントリスナをモックしたいと思うことでしょう。これにより、コントローラのHTTPレスポンスだけをテストでき、イベントリスナの実行は心配しなくて済みます。なぜなら、イベントリスナは自身のテストケースにおいて、テストできるからです。When testing Laravel applications, you may wish to "mock" certain aspects of your application so they are not actually executed during a given test. For example, when testing a controller that dispatches an event, you may wish to mock the event listeners so they are not actually executed during the test. This allows you to only test the controller's HTTP response without worrying about the execution of the event listeners, since the event listeners can be tested in their own test case.
Laravelにはイベント、ジョブ、ファサードを最初からモックできるヘルパが準備されています。これらのヘルパは主にMockery上で動作する便利なレイヤーを提供しているので、複雑なMockeryのメソッドコールを自分で作成する必要はありません。もちろん、MockeryやPHPUnitを使用し、自身のモックやスパイを自由に作成してください。Laravel provides helpers for mocking events, jobs, and facades out of the box. These helpers primarily provide a convenience layer over Mockery so you do not have to manually make complicated Mockery method calls. Of course, you are free to use Mockery[http://docs.mockery.io/en/latest/] or PHPUnit to create your own mocks or spies.
Bus FakeBus Fake
モックの別の方法は、Bus
ファサードのfake
メソッドを使用し、ジョブがディスパッチされないようにすることです。fakeを使用する場合、アサートはテスト下のコードが終了した時点で行われます。As an alternative to mocking, you may use the Bus
facade's fake
method to prevent jobs from being dispatched. When using fakes, assertions are made after the code under test is executed:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Bus;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testOrderShipping()
{
Bus::fake();
// 注文の実行コード…
Bus::assertDispatched(ShipOrder::class, function ($job) use ($order) {
return $job->order->id === $order->id;
});
// ジョブがディスパッチされないことを宣言
Bus::assertNotDispatched(AnotherJob::class);
}
}
Event FakeEvent Fake
モックの別の方法は、Event
ファサードのfake
メソッドを使用し、全イベントリスナが実行されないようにすることです。その後で、イベントがディスパッチされたことをアサートし、さらに受け取ったデータの検査もできます。fakeを使用する場合、アサートはテストを実施したコードの後に実行されます。As an alternative to mocking, you may use the Event
facade's fake
method to prevent all event listeners from executing. You may then assert that events were dispatched and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Events\OrderShipped;
use App\Events\OrderFailedToShip;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
/**
* 注文発送のテスト
*/
public function testOrderShipping()
{
Event::fake();
// 注文の実行コード…
Event::assertDispatched(OrderShipped::class, function ($e) use ($order) {
return $e->order->id === $order->id;
});
// イベントが2回ディスパッチされることをアサート
Event::assertDispatched(OrderShipped::class, 2);
// イベントがディスパッチされないことをアサート
Event::assertNotDispatched(OrderFailedToShip::class);
}
}
Note:
Event::fake()
を呼び出したあとは、イベントリスナは実行されなくなります。そのため例えば、モデルのcreating
イベントでUUIDを生成するなど、イベントに結びつけたモデルファクトリの使用をテストする場合は、ファクトリを呼び出した後に、Event::fake()
を呼び出す必要があります。{note} After callingEvent::fake()
, no event listeners will be executed. So, if your tests use model factories that rely on events, such as creating a UUID during a model'screating
event, you should callEvent::fake()
after using your factories.
限定的なEvent FakesScoped Event Fakes
テストの一部分だけでイベントをフェイクしたい場合は、fakeFor
メソッドを使用します。If you only want to fake event listeners for a portion of your test, you may use the fakeFor
method:
<?php
namespace Tests\Feature;
use App\Order;
use Tests\TestCase;
use App\Events\OrderCreated;
use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
/**
* 注文発送のテスト
*/
public function testOrderProcess()
{
$order = Event::fakeFor(function () {
$order = factory(Order::class)->create();
Event::assertDispatched(OrderCreated::class);
return $order;
});
// イベントは通常通りにディスパッチされ、オブザーバが実行される
$order->update([...]);
}
}
Mail FakeMail Fake
Mail
ファサードのfake
メソッドを使い、メールが送信されるのを防ぐことができます。その後で、Mailableがユーザーへ送信されたかをアサートし、受け取ったデータを調べることさえできます。Fakeを使用する場合、テスト対象のコードが実行された後で、アサートしてください。You may use the Mail
facade's fake
method to prevent mail from being sent. You may then assert that mailables[/docs/{{version}}/mail] were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testOrderShipping()
{
Mail::fake();
// 注文の実行コード…
Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {
return $mail->order->id === $order->id;
});
// メッセージが指定したユーザーに届いたことをアサート
Mail::assertSent(OrderShipped::class, function ($mail) use ($user) {
return $mail->hasTo($user->email) &&
$mail->hasCc('...') &&
$mail->hasBcc('...');
});
// mailableが2回送信されたことをアサート
Mail::assertSent(OrderShipped::class, 2);
// mailableが送られなかったことをアサート
Mail::assertNotSent(AnotherMailable::class);
}
}
バックグランドで送信するために、mailableをキュー投入している場合は、assertSent
の代わりにassertQueued
メソッドを使用してください。If you are queueing mailables for delivery in the background, you should use the assertQueued
method instead of assertSent
:
Mail::assertQueued(...);
Mail::assertNotQueued(...);
Notification FakeNotification Fake
Notification
ファサードのfake
メソッドを使用し、通知が送られるのを防ぐことができます。その後で、通知がユーザーへ送られたことをアサートし、受け取ったデータを調べることさえできます。Fakeを使用するときは、テスト対象のコードが実行された後で、アサートを作成してください。You may use the Notification
facade's fake
method to prevent notifications from being sent. You may then assert that notifications[/docs/{{version}}/notifications] were sent to users and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testOrderShipping()
{
Notification::fake();
// 注文の実行コード…
Notification::assertSentTo(
$user,
OrderShipped::class,
function ($notification, $channels) use ($order) {
return $notification->order->id === $order->id;
}
);
// 通知が指定したユーザーへ送られたことをアサート
Notification::assertSentTo(
[$user], OrderShipped::class
);
// 通知が送られなかったことをアサート
Notification::assertNotSentTo(
[$user], AnotherNotification::class
);
}
}
Queue FakeQueue Fake
モックの代替として、Queue
ファサードのfake
メソッドを使い、ジョブがキューされるのを防ぐことができます。その後で、ジョブがキューへ投入されたことをアサートし、受け取ったデータの内容を調べることもできます。Fakeを使う場合は、テスト対象のコードを実行した後で、アサートしてください。As an alternative to mocking, you may use the Queue
facade's fake
method to prevent jobs from being queued. You may then assert that jobs were pushed to the queue and even inspect the data they received. When using fakes, assertions are made after the code under test is executed:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Queue;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testOrderShipping()
{
Queue::fake();
// 注文の実行コード…
Queue::assertPushed(ShipOrder::class, function ($job) use ($order) {
return $job->order->id === $order->id;
});
// 特定のキューへジョブが投入されたことをアサート
Queue::assertPushedOn('queue-name', ShipOrder::class);
// ジョブが2回投入されたことをアサート
Queue::assertPushed(ShipOrder::class, 2);
// ジョブが投入されなかったことをアサート
Queue::assertNotPushed(AnotherJob::class);
}
}
Storage FakeStorage Fake
とてもシンプルにファイルアップロードのテストを行うため、Strorage
ファサードのfake
メソッドにより、UploadedFile
クラスのファイル生成ユーティリティと組み合わされたフェイクディスクを簡単に生成できます。The Storage
facade's fake
method allows you to easily generate a fake disk that, combined with the file generation utilities of the UploadedFile
class, greatly simplifies the testing of file uploads. For example:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class ExampleTest extends TestCase
{
public function testAvatarUpload()
{
Storage::fake('avatars');
$response = $this->json('POST', '/avatar', [
'avatar' => UploadedFile::fake()->image('avatar.jpg')
]);
// ファイルが保存されたことをアサート
Storage::disk('avatars')->assertExists('avatar.jpg');
// ファイルが存在しないことをアサート
Storage::disk('avatars')->assertMissing('missing.jpg');
}
}
">Tip!!
fake
メソッドはデフォルトとして、一時ディレクトリ内の全ファイルを削除します。ファイルを残しておきたい場合は、代わりにpersistentFake
メソッドを使用してください。{tip} By default, thefake
method will delete all files in its temporary directory. If you would like to keep these files, you may use the "persistentFake" method instead.
ファサードFacades
伝統的な静的メソッドの呼び出しと異なり、ファサードはモックできます。これにより伝統的な静的メソッドより遥かなアドバンテージを得られ、依存注入を使用する場合と同じテスタビリティを持てます。テスト時は、コントローラのLaravelファサード呼び出しを頻繁にモックしたくなります。例として、以下のようなコントローラアクションを考えてください。Unlike traditional static method calls, facades[/docs/{{version}}/facades] may be mocked. This provides a great advantage over traditional static methods and grants you the same testability you would have if you were using dependency injection. When testing, you may often want to mock a call to a Laravel facade in one of your controllers. For example, consider the following controller action:
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\Cache;
class UserController extends Controller
{
/**
* アプリケーションの全ユーザーリストの表示
*
* @return Response
*/
public function index()
{
$value = Cache::get('key');
//
}
}
shouldReceive
メソッドを使用し、Cache
ファサードへの呼び出しをモックできます。これはMockeryインスタンスを返します。ファサードはLaravelのサービスコンテナにより管理され、依存解決されていますので、典型的な静的クラスよりもかなり高いテスタビリティーを持っています。例としてCache
ファサードへのget
メソッド呼び出しをモックしてみましょう。We can mock the call to the Cache
facade by using the shouldReceive
method, which will return an instance of a Mockery[https://github.com/padraic/mockery] mock. Since facades are actually resolved and managed by the Laravel service container[/docs/{{version}}/container], they have much more testability than a typical static class. For example, let's mock our call to the Cache
facade's get
method:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Support\Facades\Cache;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
class UserControllerTest extends TestCase
{
public function testGetIndex()
{
Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');
$response = $this->get('/users');
// ...
}
}
Note:
Request
ファサードをモックしてはいけません。代わりに、テスト実行時はget
やpost
のようなHTTPヘルパメソッドへ、望む入力を引数として渡してください。同様に、Config
ファサードはモックを使う代わりに、テストではConfig::set
メソッドを呼び出してください。{note} You should not mock theRequest
facade. Instead, pass the input you desire into the HTTP helper methods such asget
andpost
when running your test. Likewise, instead of mocking theConfig
facade, call theConfig::set
method in your tests.