Readouble

Laravel 10.x モック

イントロダクション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メソッド呼び出しを手作業で行う必要はありません。Laravel provides helpful methods for mocking events, jobs, and other 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.

オブジェクトのモックMocking Objects

Laravelのサービスコンテナを介してアプリケーションに注入されるオブジェクトをモックする場合、モックしたインスタンスをinstance結合としてコンテナに結合する必要があります。これにより、オブジェクト自体を構築する代わりに、オブジェクトのモックインスタンスを使用するようコンテナへ指示できます。When mocking an object that is going to be injected into your application via Laravel's service container[/docs/{{version}}/container], you will need to bind your mocked instance into the container as an instance binding. This will instruct the container to use your mocked instance of the object instead of constructing the object itself:

use App\Service;
use Mockery;
use Mockery\MockInterface;

public function test_something_can_be_mocked(): void
{
    $this->instance(
        Service::class,
        Mockery::mock(Service::class, function (MockInterface $mock) {
            $mock->shouldReceive('process')->once();
        })
    );
}

これをより便利にするために、Laravelの基本テストケースクラスが提供するmockメソッドを使用できます。たとえば、以下の例は上記の例と同じです。In order to make this more convenient, you may use the mock method that is provided by Laravel's base test case class. For example, the following example is equivalent to the example above:

use App\Service;
use Mockery\MockInterface;

$mock = $this->mock(Service::class, function (MockInterface $mock) {
    $mock->shouldReceive('process')->once();
});

オブジェクトのいくつかのメソッドをモックするだけでよい場合は、partialMockメソッドを使用できます。モックされていないメソッドは、通常どおり呼び出されたときに実行されます。You may use the partialMock method when you only need to mock a few methods of an object. The methods that are not mocked will be executed normally when called:

use App\Service;
use Mockery\MockInterface;

$mock = $this->partialMock(Service::class, function (MockInterface $mock) {
    $mock->shouldReceive('process')->once();
});

同様に、オブジェクトをスパイしたい場合のため、Laravelの基本テストケースクラスは、Mockery::spyメソッドの便利なラッパーとしてspyメソッドを提供しています。スパイはモックに似ています。ただし、スパイはスパイとテスト対象のコードとの間のやり取りを一度記録するため、コードの実行後にアサーションを作成できます。Similarly, if you want to spy[http://docs.mockery.io/en/latest/reference/spies.html] on an object, Laravel's base test case class offers a spy method as a convenient wrapper around the Mockery::spy method. Spies are similar to mocks; however, spies record any interaction between the spy and the code being tested, allowing you to make assertions after the code is executed:

use App\Service;

$spy = $this->spy(Service::class);

// …

$spy->shouldHaveReceived('process');

ファサードのモックMocking Facades

従来の静的メソッド呼び出しとは異なり、ファサードリアルタイムファサードを含む)もモックできます。これにより、従来の静的メソッドに比べて大きな利点が得られ、従来の依存注入を使用した場合と同じくテストが簡単になります。テスト時、コントローラの1つで発生するLaravelファサードへの呼び出しをモックしたい場合がよくあるでしょう。例として、次のコントローラアクションについて考えてみます。Unlike traditional static method calls, facades[/docs/{{version}}/facades] (including real-time facades[/docs/{{version}}/facades#real-time-facades]) may be mocked. This provides a great advantage over traditional static methods and grants you the same testability that you would have if you were using traditional dependency injection. When testing, you may often want to mock a call to a Laravel facade that occurs 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
{
    /**
     * アプリケーションのすべてのユーザーのリストを取得
     */
    public function index(): array
    {
        $value = Cache::get('key');

        return [
            // ...
        ];
    }
}

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 Illuminate\Support\Facades\Cache;
use Tests\TestCase;

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

        $response = $this->get('/users');

        // …
    }
}

warning Warning!
Requestファサードをモックしないでください。代わりに、テストの実行時に、getpostなどのHTTPテストメソッドに必要な入力を渡します。同様に、Configファサードをモックする代わりに、テストではConfig::setメソッドを呼び出してください。[!WARNING]
You should not mock the Request facade. Instead, pass the input you desire into the HTTP testing methods[/docs/{{version}}/http-tests] such as get and post when running your test. Likewise, instead of mocking the Config facade, call the Config::set method in your tests.

ファサードのスパイFacade Spies

ファサードでスパイしたい場合は、対応するファサードでspyメソッドを呼び出します。スパイはモックに似ています。ただし、スパイはスパイとテスト対象のコードとの間のやり取りを一時的に記録しているため、コードの実行後にアサーションを作成できます。If you would like to spy[http://docs.mockery.io/en/latest/reference/spies.html] on a facade, you may call the spy method on the corresponding facade. Spies are similar to mocks; however, spies record any interaction between the spy and the code being tested, allowing you to make assertions after the code is executed:

use Illuminate\Support\Facades\Cache;

public function test_values_are_be_stored_in_cache(): void
{
    Cache::spy();

    $response = $this->get('/');

    $response->assertStatus(200);

    Cache::shouldHaveReceived('put')->once()->with('name', 'Taylor', 10);
}

時間操作Interacting With Time

テスト時、nowIlluminate\Support\Carbon::now()のようなヘルパが返す時間を変更したいことはよくあります。幸いなことに、Laravelのベース機能テストクラスは現在時間を操作するヘルパを用意しています。When testing, you may occasionally need to modify the time returned by helpers such as now or Illuminate\Support\Carbon::now(). Thankfully, Laravel's base feature test class includes helpers that allow you to manipulate the current time:

use Illuminate\Support\Carbon;

public function test_time_can_be_manipulated(): void
{
    // 未来へ移行する
    $this->travel(5)->milliseconds();
    $this->travel(5)->seconds();
    $this->travel(5)->minutes();
    $this->travel(5)->hours();
    $this->travel(5)->days();
    $this->travel(5)->weeks();
    $this->travel(5)->years();

    // 過去へ移行する
    $this->travel(-5)->hours();

    // 特定の時間へ移行する
    $this->travelTo(now()->subHours(6));

    // 現在時刻へ戻る
    $this->travelBack();
}

また、さまざまな時間移動のメソッドへ、クロージャを提供することもできます。クロージャは、指定された時刻で時間を止めたまま起動します。クロージャが実行されると、時間は通常通り再開されます。You may also provide a closure to the various time travel methods. The closure will be invoked with time frozen at the specified time. Once the closure has executed, time will resume as normal:

$this->travel(5)->days(function () {
    // 5日後の将来で、何かをテストする…
});

$this->travelTo(now()->subDays(10), function () {
    // 指定した時間で、何かをテストする…
});

freezeTimeメソッドは、現在の時刻を停止するために使用します。同様に、freezeSecondメソッドは、現在の時刻で止めますが、現在秒の先頭で止めます。The freezeTime method may be used to freeze the current time. Similarly, the freezeSecond method will freeze the current time but at the start of the current second:

use Illuminate\Support\Carbon;

// 時刻を止め、クロージャ実行後は通常どおりに再開する
$this->freezeTime(function (Carbon $time) {
    // ...
});

// 現在秒で時刻を止め、クロージャ実行後は通常通りに再開する
$this->freezeSecond(function (Carbon $time) {
    // ...
})

ご想像の通り、上記の方法はすべて、ディスカッションフォーラムで非アクティブな投稿をロックするなど、時間に敏感なアプリケーションの動作をテストするのに主に役立ちます。As you would expect, all of the methods discussed above are primarily useful for testing time sensitive application behavior, such as locking inactive posts on a discussion forum:

use App\Models\Thread;

public function test_forum_threads_lock_after_one_week_of_inactivity()
{
    $thread = Thread::factory()->create();

    $this->travel(1)->week();

    $this->assertTrue($thread->isLockedByInactivity());
}

章選択

設定

明暗テーマ
light_mode
dark_mode
brightness_auto システム設定に合わせる
テーマ選択
photo_size_select_actual デフォルト
photo_size_select_actual モノクローム(白黒)
photo_size_select_actual Solarized風
photo_size_select_actual GitHub風(青ベース)
photo_size_select_actual Viva(黄緑ベース)
photo_size_select_actual Happy(紫ベース)
photo_size_select_actual Mint(緑ベース)
コードハイライトテーマ選択

明暗テーマごとに、コードハイライトのテーマを指定できます。

テーマ配色確認
スクリーン表示幅
640px
80%
90%
100%

768px以上の幅があるときのドキュメント部分表示幅です。

インデント
無し
1rem
2rem
3rem
原文確認
原文を全行表示
原文を一行ずつ表示
使用しない

※ 段落末のEボタンへカーソルオンで原文をPopupします。

Diff表示形式
色分けのみで区別
行頭の±で区別
削除線と追記で区別

※ [tl!…]形式の挿入削除行の表示形式です。

テストコード表示
両コード表示
Pestのみ表示
PHPUnitのみ表示
和文変換

対象文字列と置換文字列を半角スペースで区切ってください。(最大5組各10文字まで)

本文フォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

コードフォント

総称名以外はCSSと同様に、"〜"でエスケープしてください。

保存内容リセット

localStrageに保存してある設定項目をすべて削除し、デフォルト状態へ戻します。

ヘッダー項目移動

キーボード操作