🐒

Go1.20でサポート予定の統合テスト用カバレッジプロファイリングを触る

2022/12/14に公開

本記事はGo Advent Calendar 2022 14日目の記事になります

Go1.20のリリースで統合テストのためのカバレッジプロファイリングがサポートされる予定です
以前まではユニットテストレベルのものでしかカバレッジを計測することができませんでしたが、go test以外のプログラムの実行や統合テストでもカバレッジの計測ができるようになるみたいです

リリースノート
https://tip.golang.org/doc/go1.20#cover

概要

  • go buildに新しいオプション-coverをつけることでカバレッジ計測可能なバイナリをビルドできる
  • バイナリ実行時にGOCOVERDIR=でプロファイルの出力フォルダを指定することでカバレッジを計測できる
  • GOCOVERDIRのデータを操作するためのツールcovdataがGo1.20で追加される
  • カバレッジ計測の仕組みを全体的に刷新する構想があり、それに準拠したアップデートになっている

使ってみる

gotip のインストール

リリース前の機能を使うのでgotipをインストールします

去年のAdvent Calenderでgotipについての記事を書きました
https://zenn.dev/uji/articles/d51e81535e0d723af56e
この記事で紹介しているインストール手順が使えます

$ go install golang.org/dl/gotip@latest
$ gotip download
$ gotip version
go version devel go1.20-b16e94d13d Mon Dec 12 23:10:52 2022 +0000 linux/amd64

テスト対象の準備

至極シンプルなコードを用意

main.go
package main

func main() {
  if false {
    // Should not be executed.
    fmt.Println("OgoOgo")
  }

  fmt.Println("GoGo")
}
go.mod
module example.com/main

go 1.20

統合テストの実施

ビルド

いつものビルドコマンドに-coverオプションを追加することで、カバレッジ計測が可能なバイナリをビルドできます

$ gotip build -cover .
$ ls
go.mod  main  main.go

実行

ビルドしたバイナリを利用して統合テスト(今回は手で実行するだけ)を実行します
実行時にGOCOVERDIR=でプロファイルの出力フォルダを指定してやることで計測結果が出力されます
GOCOVERDIRを指定せずに実行すると警告warning: GOCOVERDIR not set, no coverage data emittedが表示され、プロファイルは出力されません

$ mkdir coverdir
$ GOCOVERDIR=coverdir ./main
GoGo

指定したcoverdirディレクトリにプロファイルが出力されました

$ ls coverdir/
covcounters.5524194b4db04f800f58090476d5dc3b.741.1670935339179650175
covmeta.5524194b4db04f800f58090476d5dc3b

カバレッジはカウンターデータファイル(covcounters.xxx)とメタデータファイル(covmeta.xxx)に分かれて保存されます
メタデータファイルにはソースファイル名や関数名など実行ごとに不変な項目が保存され、カウンターデータファイルはプログラムの実行記録が保存されます
したがって、バイナリを複数回実行するとカウンターデータファイルが複数作成されます

依存パッケージがある場合、ビルド時に-coverpkgオプションも併せて利用すると依存パッケージのプロファイルのも計測できます(メインモジュールのものもここにないものは除外されます)

解析

Go1.20からGOCOVERDIRのデータを操作するためのツールcovdataが導入される予定です
percentサブコマンドを使うことでカバレッジデータを解析できます

$ gotip tool covdata percent -i=coverdir
       example.com/main        coverage: 66.7% of statements

textfmtセレクタを使うことでgo test -coverprofile=と同じ形式の出力も可能なので、
go tool cover -htmlでhtmlに変換もできます

$ gotip tool covdata textfmt -i=coverdir -o profile.txt
$ gotip tool cover -html=profile.txt -o profile.html

よく見る形式のhtmlが出力できました 

このcovdataは他にも色々サブコマンドが実装されています

usage: go tool covdata [command]

Commands are:

textfmt     convert coverage data to textual format
percent     output total percentage of statements covered
pkglist     output list of package import paths
func        output coverage profile information for each function
merge       merge data files together
subtract    subtract one set of data files from another set
intersect   generate intersection of two sets of data files
debugdump   dump data in human-readable format for debugging purposes

詳細については、新たに用意された統合テスト用カバレッジプロファイリングのガイドページをご覧ください
https://go.dev/testing/coverage/

アップデートの背景

ツールを使っていて go tool covergo test -coverといった既存の仕組みに則ることをせず、go build -covergo tool covdataという新しい仕組みを作って統合テストのカバレッジ計測を実現していることに疑問を覚えたのですが、Proposalを見るとその意図がかいてありました

https://github.com/golang/go/issues/51430

この提案は以下の課題解決を目的にしており、これは既存の仕組みでは解決しきれないもののため、カバレッジシステムを全体的に刷新しようと動いているそうです

  • アプリケーション全体でのカバレッジを計測するのが困難。複数のバイナリを利用するアプリケーションや、複数回バイナリを実行するテストシナリオに対応できない
  • 今のカバレッジレポートの形式はフラットで、大規模なアプリケーションのテストを想定したものになっていない
  • cmd/coverやgoコマンドで使用されるソースからソースへの書き換えに起因する問題がある

今後ユニットテストも含めて統合的にカバレッジ計測ができるようすることも考えているみたいで、アップデートがとても楽しみです
https://github.com/golang/go/issues/51430#issuecomment-1344711300

まとめ(冒頭の概要と同じ内容)

  • go buildに新しいオプション-coverをつけることでカバレッジ計測可能なバイナリをビルドできる
  • バイナリ実行時にGOCOVERDIR=でプロファイルの出力フォルダを指定することでカバレッジを計測できる
  • GOCOVERDIRのデータを操作するためのツールcovdataがGo1.20で追加される
  • カバレッジ計測の仕組みを全体的に刷新する構想があり、それに準拠したアップデートになっている

Discussion