Laravelプロジェクトの基本パッケージを試験対象外にする話

Laravelの基本パッケージって試験をやらないですよね。
でも、試験対象になっていてカバレッジ率が下がるのがめんどくさくないですか?
そもそもロジックもないのに試験対象に含まれているのでカバレッジ率がさがります、訳で…
チームで大体70%以上にしましょう!と言っても基本パッケージも含められると結構大変です。

今回はPHPUnitでの決められたクラス・ディレクトリを試験対象外にする方法をメモっておきます。

ちなみに、Laravelでプロジェクト新規作成直後試験を実行してみるとカバーしていないとなっています。

CUI

 Summary:               
  Classes:  0.00% (0/9) 
  Methods:  0.00% (0/10)
  Lines:    0.00% (0/24)

App\Console\Kernel
  Methods:   0.00% ( 0/ 1)   Lines:   0.00% (  0/  2)
App\Exceptions\Handler
  Methods:   0.00% ( 0/ 1)   Lines:   0.00% (  0/  1)
App\Http\Controllers\Controller
  Methods:  ( 0/ 0)   Lines:  (  0/  0)
App\Http\Kernel
  Methods:  ( 0/ 0)   Lines:  (  0/  0)
... 略

HTTPレポート

試験を実行する方法とは

忘れそうなのでPHPUnit試験の実行方法をメモっておきます

今回はphpdbgを使って楽々にしています

HTMLカバレッジレポート付き
coverageディレクトリ下にHTMLファイルが出来上がるので行単位のカバレッジが分かりやすいです

$ phpdbg -qrr vendor/bin/phpunit -c phpunit.xml --log-junit report.xml --verbose --coverage-html coverage/ --coverage-text

HTMLレポートなし

$ phpdbg -qrr vendor/bin/phpunit -c phpunit.xml --verbose --coverage-text

試験対象外を設定しまう

phpunitの設定はphpunit.xmlにあるのでそれをいじります
coverageがテストに関する部分です。
includeはテスト対象を
excludeはテスト対象外をそれぞれ指定します

    <coverage processUncoveredFiles="true">
        <include>
            <directory suffix=".php">./app</directory>
        </include>
        <exclude>
            <file >./app/Exceptions/Handler.php</file>
            <file >./app/Http/Controllers/Controller.php</file>
            <directory suffix=".php">./app/Http</directory>
            <directory suffix=".php">./app/Providers</directory>
            <directory suffix=".php">./app/Console</directory>
        </exclude>
    </coverage>

それだけです!

コミット的にはこんな感じ…
coverage範囲が対象です。下のserverがenvなのは無視してください

https://github.com/wataru775/learning-leravel/commit/c40291e1bc2e29f805f019d77a31b385b0ad8689#diff-ae310e922c85656813bd29d9f3c9a1b87c8aaa83d924813a5b91c67b7abb3cb9

個人的嗜好

入れ物は試験対象外にする

個人的に以下の無視を追加しています

・ Classesはただの入れ物クラス
・ ModelはORMのDB周りのクラス

このクラス群にはロジックは絶対に入れません!
入れそうな誘惑は無理矢理にでも別にします

なのでこいつも追加します

            <directory suffix=".php">./app/Classes</directory>
            <directory suffix=".php">./app/Models</directory>

Controllerも試験対象外にする

え?App/Httpってアクセスコントローラも!と思う超洞察力の鋭いひとに向けてですが

私はControllerにはロジックは入れません!

            <directory suffix=".php">./app/Http</directory>

・HTTPリクエストを解釈して、内部のリクエストへと変換する (もちろん別クラスで行うので呼び出しだけ)
・ 内部サービスに引き継ぐ
・ 結果を入れて返却する

こんな感じ

    public function save(Request $req): JsonResponse
    {
        // リクエストを解析します
        $saveRequest = BookRequestResponseUtil::convertSaveRequest($req);
        Log::info("api/book/save " . $saveRequest);
        // 保存処理に引き継ぎ
        $saveResponse = $this->serviceController->save($saveRequest);
        Log::info("api/book/save response " . $saveResponse);
        // 結果を返却
        return response()->json($saveResponse);
    }

ねっ、BookRequestResponseUtilにて処理をまとめているのでUnit試験も楽ちんです。
HTTP Requestをまとめているので参照時の注意も集中できます
Futures試験でも通るかなとは思いますが…

終いに

自分の関与できる範囲が絞り込めるので試験がわかりやすくなりました!

ジョブ一覧にカバレッジ率を表示させるとやる気も出ますしw

目指せ!カバー率95%以上!

やりすぎたプロジェクトw