Goのテスト結果を取得してgitlab上で見れるようにしたい 

### やりたいこと

- テストのレポートを取得したい
- テストのカバレッジを取得したい
- gitlabにその結果を反映したい

### テストのレポートを取得

最終目的はgitlab上で閲覧することなので、`JUnit XML`形式で出力できる必要があります。
そこで今回は[gotestsum](https://github.com/gotestyourself/gotestsum)を使って、テストレポートをXMLで出力します。

> gotestsum runs tests using go test --json, prints formatted test output, and a summary of the test run. It is designed to work well for both local development, and for automation like CI.

```shell
# gotestsumのインストール
go install gotest.tools/gotestsum@latest
# テストレポートをXMLで出力
gotestsum --junitfile report.xml
```

これで、XMLファイルが取得できるようになりました。gitlab-ciに組み込むと以下のようになります。

```yml:.gitlab-ci.yml
image: golang:1.18
unit test:
  stage: test
  script:
    - go install gotest.tools/gotestsum@latest
    - gotestsum --junitfile report.xml
  artifacts:
    when: always
    reports:
      junit: report.xml
```

gitlabで`CI/CD`→`Pipelines`→`該当パイプライン`→`Testsタブ`と遷移して確認すると、期待通りのレポートが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296328/02ef8f05-1d7b-bcdc-299a-29829e8a90e6.png)

gitlabの[ドキュメント](https://gitlab-docs.creationline.com/ee/ci/junit_test_reports.html#go%E3%81%AE%E4%BE%8B)では、`go-junit-report`を使った方法も紹介されています。

### テストのカバレッジを取得したい

まずは、単にカバレッジを取得したい場合、`go test`コマンドを用いて以下のように取得できます。

```sh
# パッケージごとにカバレッジを取得する
go test -cover ./...                
#=> ?       hello        [no test files]
#=> ?       hello/domain [no test files]
#=> ?       hello/infrastructure [no test files]
#=> ok      hello/repository             coverage: 10.2% of statements
#=> ok      hello/service                coverage: 82.6% of statements

# カバレッジレポートを出力
go test -coverprofile=cover.txt ./...

# 関数ごとのカバレッジと合計を出力
go tool cover -func=coverage.txt
#=> hello/repository/user.go:51:         CreateUser              60.0%
#=> ...(略)
#=> hello/service/user.go:35:            CreateUser              100.0%
#=> ...(略)
#=> total:                               (statements)            52.2%

# カバレッジレポートをHTMLに変換
go tool cover -html=cover.txt -o cover.html
```

ですが今回も先ほどと同様にXML形式で出力する必要があるので、[gocover-cobertura](https://github.com/boumenot/gocover-cobertura)を利用します。

> This is a simple helper tool for generating XML output in Cobertura format for CIs like Jenkins and others from go tool cover output.

```shell
# gocover-coberturaのインストール
go install github.com/boumenot/gocover-cobertura@latest
# カバレッジレポートをXMLで出力
go test -coverprofile=cover.txt ./...
gocover-cobertura < coverage.txt > coverage.xml
```

gitlab-ciに組み込むと以下のようになります。

```yml:.gitlab-ci.yml
image: golang:1.18
unit test:
  stage: test
  script:
    - go test -coverprofile=cover.txt ./...
    - go install github.com/boumenot/gocover-cobertura@latest
    - gocover-cobertura < coverage.txt > coverage.xml
  artifacts:
    when: always
    reports:
      cobertura: coverage.xml
```

この設定を行うことで、例えばMRで差分を確認した時に、テストコードがどの部分を網羅しているかが視覚的にわかりやすくなります。詳しくは公式ブログ(.NETですが)をご確認ください。([GitLabでコードカバレッジ](https://www.gitlab.jp/blog/2021/09/27/gitlab-coverage-dotnet/))

### gitlabにその結果を反映したい

これまで登場してきたymlファイルを統合すると以下のようになります。
```yml:.gitlab-ci.yml
image: golang:1.18
unit test:
  stage: test
  script:
    - go install gotest.tools/gotestsum@latest
    - gotestsum --junitfile report.xml -- -coverprofile=coverage.txt ./...
    - go install github.com/boumenot/gocover-cobertura@latest
    - gocover-cobertura < coverage.txt > coverage.xml
  artifacts:
    when: always
    reports:
      junit: report.xml
      cobertura: coverage.xml
```

`gotestsum`は、`--`を使うことで、`go test`の引数を指定することができます。

最後にMRやPipelineで総カバレッジ率がわかるようにymlファイルに２行だけ追加します。

```yml:.gitlab-ci.yml
image: golang:1.18
unit test:
  stage: test
  script:
    - go install gotest.tools/gotestsum@latest
    - gotestsum --junitfile report.xml -- -coverprofile=coverage.txt ./...
    - go install github.com/boumenot/gocover-cobertura@latest
    - gocover-cobertura < coverage.txt > coverage.xml
    - go tool cover -func=coverage.txt        # here
  coverage: '/total:\s+\(statements\)\s+.+%/' # here
  artifacts:
    when: always
    reports:
      junit: report.xml
      cobertura: coverage.xml
```

補足すると、`gotestsum`でカバレッジ率は出力されてはいたのですが、それは合計ではなくパッケージごとの小計のみでした。そこで、わざわざ`go tool cover`を使って総カバレッジ率を出力するようにしています。

`coverage`キーワードは、ジョブ結果出力からカバレッジを取得するためのもので、正規表現を用います。
今回は`go tool cover`の出力に合わせた正規表現を指定していて、`total: (statements) 52.2%`のような文にマッチします。

MRやPipelineで期待通りに表示できていることを確認しました。
![スクリーンショット 2022-05-02 18.56.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296328/6cf9d5f5-b55c-996e-a526-e7a61b227a51.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/296328/c16aa419-6e9a-9bee-16de-39ae9ff36dbf.png)
### 参考

[gotestsum](https://github.com/gotestyourself/gotestsum)
[go-junit-report](https://github.com/jstemmer/go-junit-report)
[gocover-cobertura](https://github.com/boumenot/gocover-cobertura)

[GitLabでコードカバレッジ](https://www.gitlab.jp/blog/2021/09/27/gitlab-coverage-dotnet/)
[GitLab:JUnitテストレポート](https://gitlab-docs.creationline.com/ee/ci/junit_test_reports.html)

[Cobertura](https://cobertura.github.io/cobertura/)