"テストカバレッジ強制ギプス" 導入

## テストカバレッジ強制ギプスとは

* テストカバレッジが**基準値以下ならマージをできなくしてしまう**機構のこと (をこの記事で勝手にそう呼んでいます)
* この記事では、**Go のプロジェクト**を運用されている方を対象に**テストカバレッジ強制ギプス**を**15分**で導入できるように紹介します
    * 具体的には、CI でテストカバレッジを計測して、[基準値以下なら fail](https://github.com/nrnrk/gotestcoveragecheck/pull/1) にさせるようにします
* テストカバレッジ強制ギプスを導入して、単体テストを充実させ快適な開発ライフを楽しみましょう

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150399/f6763328-6da4-ad39-164e-35a20f94b422.png)


## 背景

私のチームでは、 Go を用いたバックエンドサービスの開発をしています。開発の中でいくつか気になることが出てきました。

* **自動テストがあれば検知できた不具合**
* **開発コストの増大**

様々な原因がある中で、その中でも**単体テストが充実していない**ことが主要因であると分析しました。現状、問題となっているプロジェクトでは、 `E2Eテスト > 単体テスト` のカバレッジになってしまい、 E2E テストのみで検証しているロジックが増えてしまっていました。そうすることで、以下のような状況が生まれ、先程の問題が発生していると解釈しました。

* 実装時の**PDCAサイクルが大きく**なり、**実装手戻りが増える**
* **既存のコードの修正**にも**時間が余分かかる**
* テストによってカバーできていない領域が生まれ**品質が低下**する

これらの状況は**品質の低下**を招くとともに**開発体験の悪化**にも繋がります。この状況を改善するために、テストカバレッジ強制ギプスの導入をチームで実施することにしました。


## テストカバレッジ強制ギプス導入前の注意

以下の点に注意してください

* "強制ギプス" は必ずしも全ての人を幸せにしない
  * 特にすでにカバレッジが高いプロジェクトの場合は、**「やり過ぎ」になる可能性**もある
* 逆に、幸せになりやすいプロジェクトの特徴
  * **保守の割合が高い**プロジェクト
  * **現状のテストカバレッジが低い**プロジェクト
  * チーム内ですでに単体テストが不足している認識があるプロジェクト

## テストカバレッジ強制ギプス導入

では早速、テストカバレッジ強制ギプスを導入します。Go の標準ツールとbashのコマンドだけで実現していきます。


### 1. 現状のカバレッジ計測

* 対象の Go プロジェクトで以下のコマンドを実行

```shell
go test -v -coverprofile=coverage.out ./...
go tool cover -func=coverage.out
```

* 出力の最終行に注目し、合計のカバレッジを確認
    * 下の例の場合は `42.5%` なので、この値を現状のカバレッジとして記録しておく

```text:出力例
=== RUN   Test_feeling
...省略...
total:      (statements)    42.5%
```


### 2. CI 設定


* PR でトリガーされるジョブにテストカバレッジをチェックするステップを追加
    * `go build` や `go test` を実施しているところがオススメです！
    * [GithubActions の場合のサンプル](https://github.com/nrnrk/gotestcoveragecheck/blob/fa48d218e7e2592e32e1179c165c0b6f74f86554/.github/workflows/go.yaml#L24-L37)
    * [CirlceCI の場合のサンプル](https://github.com/nrnrk/gotestcoveragecheck/blob/fa48d218e7e2592e32e1179c165c0b6f74f86554/.circleci/config.yml#L11-L24)

* カバレッジの基準値を `1. 現状のカバレッジ計測` の値に変更
    * 42.5%に変更するための例: `declare -r limit=60` → `declare -r limit=42.5`

```shell:サンプル
go test -v -coverprofile=coverage.out ./...
go tool cover -func=coverage.out > report.out
# ... コメント省略 ...
# coverage rate limit
declare -r limit=60 # ←　ここの値を "1. 現状のカバレッジ計測" で得た値に変更してください
if (( $(cat report.out | awk 'END{gsub("%", "", $3); print ($3 < '$limit')}') )); then
  echo 'Coverage is below the lower limit! Failed!'
  exit 1;
fi
```

:tada: これで**テストカバレッジ強制ギプスの導入は完了**です！ :tada:

#### (CIの設定がまだない人向け)

GitHub Actions を設定しちゃいましょう！以下の手順でOKです。

* `.github/workflows/go.yaml` のファイルを作成し、[こちら](https://github.com/nrnrk/gotestcoveragecheck/blob/fa48d218e7e2592e32e1179c165c0b6f74f86554/.github/workflows/go.yaml)の中身をそのままコピー
* `1. 現状のカバレッジ計測` で計測した値で[この行](https://github.com/nrnrk/gotestcoveragecheck/blob/fa48d218e7e2592e32e1179c165c0b6f74f86554/.github/workflows/go.yaml#L33)の数値を書き換える
    * 42.5%に変更するための例: `declare -r limit=60` → `declare -r limit=42.5`



### 3. <おまけ> 動作確認

最後に動作確認しておきましょう。

* 動作確認用のブランチを作成
* テストのないロジックを追加し、PRを作成
* CI が落ちていることを確認
    * [テストカバレッジ強制ギプスによりCIが失敗したPRのサンプル](https://github.com/nrnrk/gotestcoveragecheck/pull/1)


## まとめ

* 開発体験の悪化や品質の低下を防ぐために **"テストカバレッジ強制ギプス"** を導入しました
    * サンプルレポジトリは[こちら](https://github.com/nrnrk/gotestcoveragecheck)にあるのでご参考にしてください
* **"テストカバレッジ強制ギプス"** によって、現状のテストカバレッジが下がることを防ぐことができるようになります