[PHPUnit+Xdebug/phpdbg]Laravelにコードカバレッジを設定する方法

LaravelではPHPUnitが組み込みで入っていますが、テストコードのカバレッジを可視化する機能は別で設定する必要があります。

カバレッジ(網羅率)とは、テストコードがアプリケーションのロジックをどの程度カバーできているかの割合のことです。
RPGゲームのダンジョンの踏破率とかがイメージとしては近いかもです。

テストコードを整備・管理するにあたってカバレッジ測定ができれば、
「テストコードの量は多いけど、同じロジックのテストばかりで意外とカバレッジ低かった」
「この機能のテストコードを整備してカバレッジを上げよう」
「ここは既に十分なカバレッジがあるから、そこまで注力しなくていいか」
みたいなことができます。

PHPUnitもXdebugを導入することでカバレッジ測定をできるようになるので、手順を解説していきます!


### ざっくり手順

①X-Debugの導入
②ライブラリ(`php-code-coverage`)をインストール


#### X-Debugの導入

PHPUnitのリファレンスでは、カバレッジ機能について、以下のように書いてあります。

[PHP Unitマニュアル 9. コードカバレッジ解析](https://phpunit.readthedocs.io/ja/latest/code-coverage-analysis.html)より
>  PHPUnit のコードカバレッジ解析では php-code-coverage コンポーネントを使っ
ています。このコンポーネントは、 Xdebug 拡張モジュールが提供するステートメントカバレッジ機能を利用しています。

> Xdebug は PHPUnit 本体には組み込まれていません。 テストを実行したときに no code coverage driver is available という notice が出る場合は、 Xdebug がインストールされていないかあるいはうまく設定できていないのでしょう。 PHPUnit のコードカバレッジ機能を使う前に、まずは Xdebug のインストールガイド を読んでみましょう。

ということで、まずはX-Debug導入からはじめていきます。
 
##### PHPサーバーへXdebugのインストール
まずはコマンドラインで`xdebug`をインストールします。

```shell
pecl install xdebug

....
Build process completed successfully
Installing '/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so'
install ok: channel://pecl.php.net/xdebug-3.0.3
configuration option "php_ini" is not set to php.ini location
You should add "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so" to php.ini
```

dockerを使っている場合はDockerfileのRUNに書いておくのもいいですね。

インストール後のログ(You shoud...)に従い、php.iniに設定を追記します。

```shell
# php.iniの場所を確認
$ echo $PHP_INI_DIR
/usr/local/etc/php

# php.iniファイルを編集
# ログに出力された "zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20190902/xdebug.so" を追記
$ cd /usr/local/etc/php
vi php-base.ini
```
追記する内容は環境ごとに異なる可能性があるので、実際に表示されたログを元にしましょう。


最後に、php.iniの編集を反映するためサーバーを再起動します。

```shell
find -type f -naem apache

/etc/init.d/apache2 reload

[ ok ] Reloading Apache httpd web server: apache2.
```
これでXdebugのインストール+PHPの設定は完了しました。

##### `phpunit/php-code-coverage`の導入
composerでライブラリをインストールします。

```shell
composer require --dev phpunit/php-code-coverage
```

#### コマンドの実行・scriptの追記
ここまでやれば導入できているので、コマンドを打って確認してみましょう。

```shell
XDEBUG_MODE=coverage ./vendor/bin/phpunit ./tests --coverage-html reports
```

HTMLでカバレッジレポートが生成されるのを確認できたら、composer.jsonにscriptsとして設定しておくと便利です。


```json:composer.json
    "scripts": {
        "test:coverage-xml": [
        "@putenv XDEBUG_MODE=coverage",
        "./vendor/bin/phpunit --color=always --coverage-clover=\"storage/logs/code-coverage/clover.xml\""
        ],
        "test:coverage-html": [
        "@putenv XDEBUG_MODE=coverage",
        "./vendor/bin/phpunit --color=always --coverage-html=\"storage/logs/code-coverage\""
        ],
```

HTML形式で出力されたレポートをブラウザで表示すると↓のようなデザインで確認することができます!
自分の場合は、カバレッジが低すぎる現状が数字でわかるようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420171/92ff0f77-eaf5-dbb7-39db-8b5c2e0f0ebe.png)


#### より高速にレポート出力できるphpdbgを使う
phpdbgは、PHP5.6より採用されている対話型デバッガです。
デフォルトのXdebugでのカバレッジレポートが出せていれば、
phpdbgをドライバに使えます。

phpdbgを使うにはコマンドの頭に`phpdbg -qrr`をつけるだけ!

```json:composer.json
    "scripts": {
        "test:coverage": [
        "phpdbg -qrr ./vendor/bin/phpunit --color=always --coverage-clover=\"storage/logs/code-coverage/clover.xml\""
        ],
        "test:coverage-html": [
        "phpdbg -qrr ./vendor/bin/phpunit --color=always --coverage-html=\"storage/logs/code-coverage\""
        ],
```

Xdebugとphpdbgの実行時間の比較は↓が参考になるかと。
参考:[php7 + phpdbgで高速カバレッジ出力](https://matchingood-engineer.hatenablog.com/entry/2017/03/17/193521)

手間もほぼ0なので、忘れずに設定しておきましょう。

#### トラブルシューティング

##### Xdebug導入がうまくいかない時
環境の違いなどで手順通りにやっても導入できない時は、Xdebugリファレ
ンスのwizardを元に導入を進めるのがおすすめです。
[Xdebug Installation Wizard](https://xdebug.org/wizard)

・手順
① phpinfo()で設定情報を出力

```shell
php -r 'phpinfo();' > phpinfo.txt
```

②ファイル内容をwizardのインプットに貼り付ける

③状態に応じて手順が表示されるので、ガイドにしたがってインストール

##### その他

```shell
PHP:  syntax error, unexpected end of file, expecting TC_DOLLAR_CURLY or TC_QUOTED_STRING or '"' in /usr/local/etc/php/conf.d/php-base.ini on line 18
```
となった場合、php-iniに書く設定末尾は"" で終わっているようにする(xdbugの設定を他の設定より上にする)で解決しました。


#### 参考資料

・カバレッジ
[Teach matrix カバレッジ(網羅率)分析とは](https://www.techmatrix.co.jp/t/quality/coverage.html#:~:text=%E3%82%AB%E3%83%90%E3%83%AC%E3%83%83%E3%82%B8%E3%81%AF%E3%80%81%E6%89%80%E5%AE%9A%E3%81%AE%E7%B6%B2%E7%BE%85,%E5%89%B2%E5%90%88%E3%82%92%E6%84%8F%E5%91%B3%E3%81%97%E3%81%BE%E3%81%99%E3%80%82)

・Xdebug
[Xdebug 公式インストールページ](https://xdebug.org/docs/install)
[packagist phpunit/php-code-coverage](https://packagist.org/packages/phpunit/php-code-coverage)
[PHP開発者がいまさら聞けない、Xdebugの基礎の基礎](https://www.webprofessional.jp/getting-know-love-xdebug/)
[MacでXdebugを有効にする](http://coelacanth.jp.net/mac_xdebug/)
[Github php-code-coverage ISSUE:Support XDEBUG_MODE environment variable](https://github.com/sebastianbergmann/php-code-coverage/issues/834)

・phpdbg
[phpdbg 簡易マニュアル](https://gist.github.com/hotta/8246028005595bf08662)