NAKKA-Kの技術ブログ

技術に関する知見や考え方などを投稿します。

Laravel5.7のServiceコンテナをモック化してする方法

Laravelに限らずですが外部のAPIを通信したり、重い処理を実行しているの部分があるのでテストの時はモックにしたい、といった場面は多々あると思います。 今回はServiceコンテナをモック化する方法をまとめていきます。

Serviceコンテナが使われているコード

    public function store(Request $request, User $user)
    {
        // ScrapeManagerの生成
        $scrapers = resolve('app.bookInfo.scrapeManager');

        // ScrapeManagerの実行
        $newBook = $scrapers->searchByIsbn((string)$isbn);

        // ......

Serviceコンテナのキーを使ってresolveで生成しています。 この中身をモック化できればいい感じにテストができそうです。

(Managerなんて責務の大きい名前を使ってんじゃねぇ、という意見は却下します)

テスト内でモック化する

    public function setUp()
    {
        // モックを作成
        $mock = \Mockery::mock(ScrapeManager::class)
            ->shouldReceive('searchByIsbn')
            ->andReturn($this->book)
            ->getMock();

        // モックを適用
        $this->app->bind('app.bookInfo.scrapeManager', function() use ($mock) {
            return $mock;
        });
    }

    public function tearDown()
    {
        parent::tearDown();
        \Mockery::close();
    }

実はこれだけです。 Mockery::mockでモック化対象のクラスを指定します。 shouldReceiveで対象メソッドを指定します。 andReturnで対象メソッドの戻り値を設定します。 あとは最後にgetMockを実行してモックのインスタンスを獲得することを忘れないようにしてください。

次に作成したモックをresolveで解決できる形に設定する必要があります。 $this->app->bindを使います。 第一引数にresolve時に使うキーを指定し、第二引数にはモックを返す関数を設定します。

テスト終了後にMockery::close()を実行することを忘れないようにしましょう。

あとはただただテストをするだけです。 そうすれば処理の中でモック化したキーのresolveが使われれば、モックオブジェクトが呼び出されて任意の処理になります。

テストについて

Laravelでコントローラーテストをする場合にはこちらの記事をご覧ください。

nakka-k.hatenablog.com

まとめ

処理の重い部分、特に外部に影響を与える部分はちゃんとモック化しましょう!! 良いテスト生活を!