Laravel 5.3 モック

イントロダクション

Laravelアプリケーションをテストする場合、特定のテストの間は実際に実行されないように、アプリケーションの明確な一部を「モック」したくなります。たとえば、イベントを発行するコントローラをテストする時に、テストの間は実際に実行したくないので、イベントリスナーをモックしたいと思うことでしょう。これにより、コントローラのHTTPレスポンスだけをテストし、イベントリスナーの実行を心配しなくて済みます。なぜなら、イベントリスナーは自身のテストケースにおいて、テストできるからです。

Laravelにはイベント、ジョブ、ファサードを最初からモックできるヘルパが準備されています。これらのヘルパは主にMockery上で動作する便利なレイヤーを提供しているので、複雑なMockeryのメソッドコールを自分で作成する必要はありません。もちろん、MockeryやPHPUnitを使用し、自身のモックやスパイを自由に作成してください。

イベント

モックの使用

Laravelのイベントシステムを多用している場合、テスト中は静かにしてもらうか、特定のイベントモックしたいと思うでしょう。たとえばユーザ登録のテスト中は、たぶんUserRegisteredイベントのハンドラには全部起動してもらいたくないでしょう。なぜなら、"Welcome"メールが送られて…などが起きるからです。

Laravelはイベントハンドラを実行させずに期待するイベントが発行されたことを確認する、便利なexpectsEventsメソッドを用意しています。

<?php

use App\Events\UserRegistered;

class ExampleTest extends TestCase
{
    /**
     * 新ユーザの登録テスト
     */
    public function testUserRegistration()
    {
        $this->expectsEvents(UserRegistered::class);

        // ユーザ登録のテスト…
    }
}

指定したイベントが発行されないことを確認するには、doesntExpectEventsメソッドを使います。

<?php

use App\Events\OrderShipped;
use App\Events\OrderFailedToShip;

class ExampleTest extends TestCase
{
    /**
     * 注文発送のテスト
     */
    public function testOrderShipping()
    {
        $this->expectsEvents(OrderShipped::class);
        $this->doesntExpectEvents(OrderFailedToShip::class);

        // 注文発送のテスト…
    }
}

全イベントハンドラの実行を停止したい場合は、withoutEventsメソッドを使用してください。このメソッドが呼び出されると、全イベントの全リスナーはモックされます。

<?php

class ExampleTest extends TestCase
{
    public function testUserRegistration()
    {
        $this->withoutEvents();

        // ユーザ登録コードのテスト…
    }
}

Fakeの使用

モックの代替として、Eventファサードのfakeメソッドを使い、全イベントリスナーの実行を停止できます。その後に、発行されたイベントをアサートし、受け取ったデータを調べることも可能です。Fakeを使用する場合、テスト対象のコードを実行した後に、アサートを作成してください。

<?php

use App\Events\OrderShipped;
use App\Events\OrderFailedToShip;
use Illuminate\Support\Facades\Event;

class ExampleTest extends TestCase
{
    /**
     * 注文のテスト
     */
    public function testOrderShipping()
    {
        Event::fake();

        // 注文の実行コード…

        Event::assertFired(OrderShipped::class, function ($e) use ($order) {
            return $e->order->id === $order->id;
        });

        Event::assertNotFired(OrderFailedToShip::class);
    }
}

ジョブ

モックの使用

時には、アプリケーションへリクエストを作成したら、特定のジョブがディスパッチされるかをテストしたいこともあるでしょう。これによりジョブのロジックについて心配せずに、切り離してルートやコントローラをテストできます。もちろん、それから切り離したテストケースで、ジョブをテストすべきです。

Laravelは便利なexpectsJobsメソッドを用意しており、期待しているジョブがディスパッチされたかを検査できます。しかしジョブ自身は実行されません。

<?php

use App\Jobs\ShipOrder;

class ExampleTest extends TestCase
{
    public function testOrderShipping()
    {
        $this->expectsJobs(ShipOrder::class);

        // 注文の発送をテスト…
    }
}

Note: このメソッドはDispatchesJobsトレイトのdispatchメソッドか、dispatchヘルパ関数により起動されたジョブだけを検知します。直接Queue::pushで送られたジョブは検知できません。

イベントモックヘルパのように、doesntExpectJobsメソッドを利用し、ジョブをディスパッチせずにテストできます。

<?php

use App\Jobs\ShipOrder;

class ExampleTest extends TestCase
{
    /**
     * 注文キャンセルのテスト
     */
    public function testOrderCancellation()
    {
        $this->doesntExpectJobs(ShipOrder::class);

        // 注文キャンセルのテスト…
    }
}

もしくは、withoutJobsメソッドを使い、全ディスパッチジョブを無効にできます。あるテストメソッド内でこのメソッドを呼び出すと、そのテストの間にディスパッチされた全ジョブは破棄されます。

<?php

use App\Jobs\ShipOrder;

class ExampleTest extends TestCase
{
    /**
     * 注文キャンセルのテスト
     */
    public function testOrderCancellation()
    {
        $this->withoutJobs();

        // 注文キャンセルのテスト…
    }
}

Fakeの使用

モックの代替として、Queueファサードのfakeメソッドを使い、ジョブがキューされるのを防ぐことができます。その後で、ジョブがキューへ投入されたことをアサートし、受け取ったデータの内容を調べることもできます。Fakeを使う場合は、テスト対象のコードを実行した後で、アサートしてください。

<?php

use App\Jobs\ShipOrder;
use Illuminate\Support\Facades\Queue;

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);

        // ジョブが投入されなかったことをアサート
        Queue::assertNotPushed(AnotherJob::class);
    }
}

MailのFake

Mailファサードのfakeメソッドを使い、メールが送信されるのを防ぐことができます。その後で、Mailableがユーザへ送信されたかをアサートし、受け取ったデータを調べることさえできます。Fakeを使用する場合、テスト対象のコードが実行された後で、アサートしてください。

<?php

use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;

class ExampleTest extends TestCase
{
    public function testOrderShipping()
    {
        Mail::fake();

        // 注文コードの実行…

        Mail::assertSent(OrderShipped::class, function ($mail) use ($order) {
            return $mail->order->id === $order->id;
        });

        // メッセージが指定したユーザに届いたことをアサート
        Mail::assertSentTo([$user], OrderShipped::class);

        // Mailableが送られなかったことをアサート
        Mail::assertNotSent(AnotherMailable::class);
    }
}

NotificationのFake

Notificationファサードのfakeメソッドを使用し、通知が送られるのを防ぐことができます。その後で、通知がユーザへ送られたことをアサートし、受け取ったデータを調べることさえできます。Fakeを使用するときは、テスト対象のコードが実行された後で、アサートを作成してください。

<?php

use App\Notifications\OrderShipped;
use Illuminate\Support\Facades\Notification;

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
        );
    }
}

ファサード

伝統的な静的メソッドの呼び出しと異なり、ファサードはモックできます。これにより伝統的な静的メソッドより遥かなアドバンテージを得られ、依存注入を使用する場合と同じテストビリティを持てます。テスト時、コントローラのLaravelファサード呼び出しを頻繁にモックしたくなります。たとえば、以下のようなコントローラアクションを考えてください。

<?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メソッド呼び出しをモックしてみましょう。

<?php

class FooTest extends TestCase
{
    public function testGetIndex()
    {
        Cache::shouldReceive('get')
                    ->once()
                    ->with('key')
                    ->andReturn('value');

        $this->visit('/users')->see('value');
    }
}

Note: Requestファサードはモックしてはいけません。テスト実行時は代わりに、callpostのようなHTTPヘルパメソッドへ望みの入力を渡してください。同様に、テストではConfigファサードをモックする代わりに、Config::setメソッドを呼び出してください。

ドキュメント章別ページ

開発環境
ビューとテンプレート
Artisanコンソール
公式パッケージ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる