🌻

Laravel テスト用の独自ヘルパーメソッドを使った際のプチ裏技

2024/12/10に公開

前書き

Laravel でテストを書く際、お決まりな処理をまとめた独自ヘルパーメソッドを使ったりすると便利な事があります。しかし良くなる面がある一方、テストに失敗した際に失敗箇所が分かりにくくなったりする面もあります。今回はそんな時に使えるかも知れない裏技について書いてみたいと思います。

あくまで「裏技」ですので、そういう認識で軽く読んでいただければと思います😅 いつ無効になるかも分かりません。

なお、この裏技自体は PHPUnit でも実現可能ですが、この記事では Pest を前提で書いています。Pest はまだよく分からない、という方は こちらの Udemy 講座 なんかもよろしくお願いします。(キャンペーンコードは、YYYY-MM 形式。例:2024-12)

本題

例えば、下記みたいなテストがあったとします。

test('example', function () {
    $this->get('/')
        ->assertOk();
});

->get() の後に ->assertOk() をするのは、もうお決まりですね。

もしここでテストに失敗した場合は、下記のような出力結果になります。

  at tests/Feature/Http/Controllers/FooControllerTest.php:5
      1▕ <?php
      23test('example', function () {
      4$this->get('/')5->assertOk();
      6});

どこでエラーになったかすぐ分かりますね。👍

さて、上記のようなテストはお決まりです。そこで下記みたいに書けたらスッキリしそうです。

test('example', function () {
    getOk('/');
});

Pest でこれを実現するには、Pest.php に下記のようなコードを追記すれば OK です。(Pest ドキュメント)

tests/Pest.php
use Illuminate\Testing\TestResponse;

function getOk(...$args): TestResponse
{
    return test()->get(...$args)->assertOk();
}

これで、テストコードもスッキリします。

ただ、ここでプチ問題が発生します。テストに失敗した際の出力結果が退化します🥲 下記みたいになります。

  at tests/Pest.php:49
     45*/
     4647function getOk(...$args): TestResponse
     48{49return test()->get(...$args)->assertOk();
     50}
     521   tests/Feature/Http/Controllers/FooControllerTest.php:4

矢印(➜)で指している場所が、Pest.php のファイルを指してしまいました😖
まぁ、確かにそこに assertOk() と記述してあるので、そこで失敗したのは確かなのですが、できれば最初の時のように、その呼び出し元の箇所を指摘してほしい所です。(幸い、今時の Laravel であれば、出力結果の最下行を見れば、呼び出し元のファイル名と行数は分かったりはしますが…)

そこで裏技の登場です。新規にファイル tests/bin/pest/functions.php を作成し、先程 Pest.php に追記した分をこちらに移動します。

tests/bin/pest/functions.php
<?php

use Illuminate\Testing\TestResponse;

function getOk(...$args): TestResponse
{
    return test()->get(...$args)->assertOk();
}

Pest.php は、代わりに最下部辺りに下記を追記します。

require 'bin/pest/functions.php';

これで、テストに失敗した際の出力結果が、最初のパターンに戻ります👍

裏技の仕組みは?

Laravel では、nunomaduro/collision というライブラリが、テストで失敗した際のエラー箇所を分かり易く表示してくれています。

そして、Laravel フレームワーク内でアサートして失敗した場合は、その箇所は、エラーの箇所(矢印(➜)で示す箇所)としては、(概ね)除外されるようになっていて、その呼び出し元がエラー箇所として表示されるようになっています。(丁度、上記で見たように)

それは、この辺りのコードからも分かります。

一部抜粋
        $writer->ignoreFilesIn([
            '/bin\/pest/',
            '/vendor\/pestphp\/pest/',
            '/Illuminate\/Testing/',
            '/Illuminate\/Foundation\/Testing/',
            '/Illuminate\/Foundation\/Bootstrap\/HandleExceptions/',

            // 一部抜粋
        ]);

除外する仕組みとしては、上記コードで列挙されたファイルパスに合致すれば、そのファイルは出力結果からは除外される事になります。その為、bin/pest/functions.php というやや微妙なファイル名にヘルパー関数を記述する事により、エラーの出力結果からは除外されたという訳です。

雑感

あくまで裏技という感じになります。

「いや、そんな裏技使わなくてももっといい方法あるよ!」という内容ご存じでしたら、コメントお願いします🙇‍♂️

Discussion