---
title: なぜGoのカバレッジはstmtとfnなのか
tags:  #go  
author: [Rinrin](https://www.docswell.com/user/rin2yh)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/VEPKV29D78.jpg?width=480
description: Asakusa.go #8のスライドです。 なぜGoのカバレッジはstmtとfnなのか、Goのカバレッジ計測を利用した時に感じた小さな疑念を発端に調査結果をまとめました。Goが選んだ選択と思想、そこから見えてくるカバレッジについて話します。
published: July 03, 26
canonical: https://www.docswell.com/s/rin2yh/K277VM-why-does-Go-use-statements-and-functions-for-coverage
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/VEPKV29D78.jpg)

Asakusa.go #8
なぜGoのカバレッジはstmtとfnなのか
Rinrin
#asakusago


# Page. 2

![Page Image](https://bcdn.docswell.com/page/27VVZDMG7Q.jpg)

自己紹介
名前
職種
趣味
歴
Go
ひとこと
Rinrin
フルスタックエンジニア
アニメ、ゲーム、キーボード
2年
asakusaは3〜4回遊びに。美味しいもの
多い！
02


# Page. 3

![Page Image](https://bcdn.docswell.com/page/5JGL4YXD7L.jpg)

目次
導入
2. Goの選択とその理由
3. 仕組み
4. まとめ
1.
03


# Page. 4

![Page Image](https://bcdn.docswell.com/page/47QYGM8XEP.jpg)

導入
SECTION 01
04


# Page. 5

![Page Image](https://bcdn.docswell.com/page/KE4W5V22J1.jpg)

Goのカバレッジで取れるのはstmtとfnだけ?
statement
全体で取れる
$ go test -cover
coverage: 80.0% of statements
function
ごとに取れる
$ go tool cover -func
grade.go:4: Grade
80.0%
Vitest
は branch も取れる
% Stmts | % Branch | % Funcs | % Lines
Vitest では branch も取れるのに、なぜGoは取れないのか?
05


# Page. 6

![Page Image](https://bcdn.docswell.com/page/L71YW3MKJG.jpg)

Goの選択と
その理由
SECTION 02
06


# Page. 7

![Page Image](https://bcdn.docswell.com/page/G7WG6P3PE2.jpg)

計測にはバイナリ計測とソースコード計測の2系統がある
ソースコード計測
バイナリ計測
コンパイル前にソースを
書き換えてカウンタを挿入
ソースコード
実行中のバイナリを外から監視し、
どこが実行されたか記録する
コンパイル
実行
Goはどちらを選んだのか。
07


# Page. 8

![Page Image](https://bcdn.docswell.com/page/4JZLYKV6E3.jpg)

ソースコード計測
方式
ソースコード計測（Go cover）
移植性
高い：AST だけで完結し、環境に依存しない
バイナリ計測（gcov, V8）
低い：OS / CPU / debug info に依存し、環境ごとに実装が必要になる
&quot;For the new test coverage tool for Go, we took a different approach that avoids dynamic debugging. The idea is
simple: Rewrite the package&#039;s source code before compilation to add instrumentation...&quot;
— The cover story, Rob Pike, The Go Blog (2013)
Go標準ライブラリの構文解析・整形パッケージで実現。Pikeが最重視した弱点の移植性を回避できる。
08


# Page. 9

![Page Image](https://bcdn.docswell.com/page/YE6WDQ5LEV.jpg)

計測の単位はブロック
ソースコード計測では、AST をどの単位で区切って計測するかを選べる。分岐はソース上に明示的に現れないため、
波括弧で区切られたブロックが自然な単位になる。
単位
ブロック単位（Go cover）
式・条件単位
分かること
ブロックが実行されたか
branch / condition
コスト
軽い
重い
仕組み
ブロック先頭にカウンタ1つ
&amp;&amp; / || を分岐へ展開し、オペランドごとにカウンタ
ブロック（basic block）とは、if / for / range / switch / type switch / select、break・continue・goto・
fallthrough、ラベル付き文、ネストした { }、panic() で区切られた区間。
デメリットは、ブロック内部の分岐を細かく計測できないこと。
＝Goで branch を計測できず、取れない
09


# Page. 10

![Page Image](https://bcdn.docswell.com/page/GE5M3RYME4.jpg)

仕組み
SECTION 03
10


# Page. 11

![Page Image](https://bcdn.docswell.com/page/9729ZDGRJR.jpg)

計測したいソースコード
例：整数の絶対値を返す Abs 関数。Abs(3)で1回だけテストを実行してみる。
func Abs(n int) int {
if n &lt; 0 {
return -n
}
return n
}
11


# Page. 12

![Page Image](https://bcdn.docswell.com/page/DJY4R2V57M.jpg)

コンパイル前にカウンタ配列を作る
各ブロックの先頭にカウンタを 1 つ挿入。3ブロックなので長さ 3 の配列ができる。
func Abs(n int) int {
GoCover.Count[0] = 0
if n &lt; 0 {
GoCover.Count[1] = 0
return -n
}
GoCover.Count[2] = 0
return n
}
12


# Page. 13

![Page Image](https://bcdn.docswell.com/page/V7NYD8M4E8.jpg)

テスト実行時にカウンタ配列を更新
Abs(3)
の時、n &lt; 0 は偽なので return -n のブロックは通らない。
func Abs(n int) int {
GoCover.Count[0] = 1
if n &lt; 0 {
GoCover.Count[1] = 0
return -n
}
GoCover.Count[2] = 1
return n
}
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/YJ9PGKN473.jpg)

集計
Abs(3)
を 1 回テストした場合
ブロック
①
②
③
合計
カウンタ
場所
Count[0]
if n &lt; 0
Count[1]
return -n
Count[2]
return n
文
stmt数
1
1
1
3
実行
✓
✗
✓
2
命令網羅（stmt） = 実行 stmt ÷ 全 stmt = 2 / 3 = 66.7%
実行結果（ツール出力）
$ go tool cover -func
abs.go:2: Abs 66.7%
14


# Page. 15

![Page Image](https://bcdn.docswell.com/page/GJ8DVRKVJD.jpg)

まとめ
SECTION 04
15


# Page. 16

![Page Image](https://bcdn.docswell.com/page/LJLM5KZRER.jpg)

Q. なぜGoのカバレッジはstmtとfnなのか?
A. ブロック単位のソースコード計装を行っているから
2 つの決定と、その理由
1. 計測方式は ソースコード計測
理由 AST だけで完結し環境に依存しない＝移植性が高いから
2. 計測単位は ブロック単位
理由 ソース書き換えでは分岐がソース上に現れず、波括弧で区切られたブロックが自然な単位だから
16


# Page. 17

![Page Image](https://bcdn.docswell.com/page/47MY32VP7W.jpg)

Thank you
ご清聴いただき、
ありがとうございました
Rinrin / @rin2yh
#asakusago
17


# Page. 18

![Page Image](https://bcdn.docswell.com/page/P7R9QM2YE9.jpg)

参考文献
Rob Pike「The cover story」The Go Blog, 2013
https://go.dev/blog/cover
Go cover ツール実装 src/cmd/cover/
https://github.com/golang/go/tree/master/src/cmd/cover
高橋寿一『知識ゼロから学ぶソフトウェアテスト 第3版 ― アジャイル・AI時代の必携教科書』翔泳社, 2024
https://www.shoeisha.co.jp/book/detail/9784798182452
Vitest 公式ドキュメント「Coverage」
https://vitest.dev/guide/coverage.html
18


