Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
AI時代を見据えたコードカバレッジ計測ツールの開発
Search
Masaaki Goshima
February 23, 2026
Programming
54
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
AI時代を見据えたコードカバレッジ計測ツールの開発
Masaaki Goshima
February 23, 2026
More Decks by Masaaki Goshima
See All by Masaaki Goshima
Goにおけるインナーソースモデル構築への道のり
goccy
1
410
Go で WebAssembly を利用した 実用的なプラグインシステムの構築方法
goccy
8
4k
BigQueryエミュレータの作り方
goccy
1
5.6k
GoとJSON
goccy
1
220
エンジニアリングを支援するための様々なかたち
goccy
0
1.9k
最速のJSONライブラリを求めて
goccy
16
13k
PWAゲームを開発しネイティブアプリ化までした中での課題と対策
goccy
7
5k
Other Decks in Programming
See All in Programming
LLM本来の能力を解き放つサンドボックス技術とAI民主化への適用
yukukotani
3
3.9k
Java × distroless で 軽量なコンテナイメージを / Java on Distroless
contour_gara
0
540
コンテキストの使い捨てをやめる — ビジネスルール駆動開発と miko —
ioki
0
200
Language Server 使ってる? 〜VSCode と Zed の場合〜 / Are you using a Language Server? ~For VS Code and Zed~
handlename
0
780
net-httpのHTTP/2対応について
naruse
0
480
Creating Composable Callables in Contemporary C++
rollbear
0
130
不変条件と整合性境界—ビジネスが決める設計判断と実現パターン / Invariants and Consistency Boundaries
nrslib
13
4k
AI時代の仕事技芸論 — ソフトウェア開発で「遊ぶように働く」職人的熟達のすすめ
kuranuki
2
670
Inside Stream API
skrb
1
710
Lemonade + Foundry Toolkit でお手軽アプリ開発
seosoft
1
330
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
130
過去最大のMCPアップデート! 2026-07-28 RC版の謎に迫る
licux
6
310
Featured
See All Featured
Speed Design
sergeychernyshev
33
1.8k
AI: The stuff that nobody shows you
jnunemaker
PRO
8
710
Amusing Abliteration
ianozsvald
1
200
SEO in 2025: How to Prepare for the Future of Search
ipullrank
3
3.5k
職位にかかわらず全員がリーダーシップを発揮するチーム作り / Building a team where everyone can demonstrate leadership regardless of position
madoxten
62
54k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
12
1.7k
Helping Users Find Their Own Way: Creating Modern Search Experiences
danielanewman
31
3.2k
How to Talk to Developers About Accessibility
jct
2
230
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
55
3.4k
Documentation Writing (for coders)
carmenintech
77
5.4k
How to optimise 3,500 product descriptions for ecommerce in one day using ChatGPT
katarinadahlin
PRO
1
3.6k
Transcript
AI時代を見据えた コードカバレッジ計測ツールの開発 Go Conference mini 2026 in Sendai goccy
Go Conference mini 2026 in Sendai 自己紹介 • goccy (
ごっしー ) ◦ Twitter(新X): @goccy54 / GitHub: @goccy • 仙台市泉区出身 • Go リポジトリの総獲得 Star 数:10K+ ◦ 個人OSS: go-json / go-yaml / bigquery-emulator etc. ◦ 企業OSS: grpc-federation etc. • Go Conference mini 2022 in Sendai ◦ BigQueryエミュレータの作り方
Go Conference mini 2026 in Sendai Agenda • Motivation ◦
なぜ新しいコードカバレッジツールが必要だと思ったのか • Tobari ◦ AI時代を見据えたコードカバレッジツールの紹介 • How it Works ◦ どうやって作ったのか
Go Conference mini 2026 in Sendai Motivation
Go Conference mini 2026 in Sendai AI時代の開発と品質保証 AI (Coding Agentなど)
により開発速度が上がっている一方、 その品質保証を人間が担う部分で律速になる課題がある • 大量のPRのレビュー / 人が行うQAプロセス 自動テストで品質保証する重要性が高まる 品質保証するために必要十分なテストとは? 課題 テストカバレッジが 100% に近いテストと定義 100%に近いコードカバレッジを 提供するテストを 効率よく生成したい
Go Conference mini 2026 in Sendai Go のカバレッジツールが抱える課題 Granularity (
計測粒度 ) Isolation ( 計測対象の隔離 )
Go Conference mini 2026 in Sendai Granularity ( 計測粒度 )
の課題 • テスト全体で通った場所はわかるが、どのテストで通ったかはわからない TestA ( X% coverage ) TestB ( Y% coverage ) TestA + TestB = 100% coverage X is 0% or 30 % or 50% or 100% ….?
Go Conference mini 2026 in Sendai Isolation ( 計測対象の隔離 )
の課題 • runtime/coverage を使った go test 以外の計測を考える ◦ e.g.) HTTP / gRPC Server に対するリクエストによる計測 • テストと関係のないカバレッジを取るリスクがある 1 5 2 6 Coverage Request A Coverage Request B Normal Request Goroutines 3 4 gRPC or HTTP Server 数字: 処理順 6 を処理したあとに カバレッジを取得すると、 1~6 すべてが結果に含まれる 本当は 1と6の結果だけ欲しい
Go Conference mini 2026 in Sendai Coding Agent がテストを生成する際の影響 •
テストごとのカバー範囲が正確にわからないため、全体で 100% に近づける ようにテストケースを作成する • 同じカバー範囲のテストが大量に作られる可能性がある ◦ CI の時間・費用、レビューやメンテナンスのコストが増える CI Time Review Cost Maintenance Cost
Go Conference mini 2026 in Sendai あるテストによって、どの部分がカバーされたのかを正確に把握できれば、 Coding Agent が意味的に重複がないテストを生成する精度が上がるのでは?
Go のコードカバレッジ計測ツールを自作し、検証することに 仮説 検証
Go Conference mini 2026 in Sendai Tobari - 帷 -
Go Conference mini 2026 in Sendai Tobari - 帷 -
• github.com/goccy/tobari • テストごとに通過した場所を正確に記録することができる • go test で使ったり、 runtime/coverage と同じように Server でも使える ◦ Goのカバレッジ計測ツールの代わりに使える • Install: go install github.com/goccy/tobari/cmd/tobari@latest
Go Conference mini 2026 in Sendai How to use •
with go test1 ◦ GOFLAGS=$(tobari flags) go test ./… ▪ tobari flags: -cover -toolexec=tobari を出力 ▪ 実行すると tobari/tobari.(json|toon) が作られる ▪ テスト対象を一切変更する必要がない • NOT go test1 ◦ gRPC Server InterceptorやHTTP adapterの中で、カバレッジリクエストのと きに tobari.CoverWithName(name, entryFunc) を呼ぶ ▪ name : カバレッジを分けたい単位で設定する識別子 ▪ entryFunc : カバレッジを取得し始めるエントリ関数
Go Conference mini 2026 in Sendai 計測結果の利用方法 • HTML 表示機能を利用してカバレッジ範囲を目視で改善
• Tobari の Agent Skills を使ったテストコードの自動改善
Go Conference mini 2026 in Sendai How it Works
Go Conference mini 2026 in Sendai (前提) Go のカバレッジ計測の仕組み 1.
go (test|build|run) のときに -cover option をつける 2. Goコンパイラがカバレッジ対象のパッケージを特定し、 そのパッケージのファイルを引数に go tool cover を呼び出す 3. go tool cover の中で受け取ったソースコードを AST に変換 4. AST からカバレッジ計測ポイント ( 関数の先頭や Ifによる分岐など ) を見つけ、 カウンタを挿入したコードを生成 5. 生成したファイルの場所を go tool cover の -outfilelist option で指定したファイルに書く 6. go tool compile が生成したコードを対象に走ってカバレッジ付きのバイナリになる go test -cover ./ Go compiler go tool cover Instrumented Code go tool compile Binary with coverage Identify cover targets AST transform Insert counters
Go Conference mini 2026 in Sendai Key Idea: Coverage with
GoroutineID 1. go tool cover の実行を自前のツールに差し替える 2. ASTを編集して計測ポイントを追加する際に、親と自分の GoroutineID も一緒に保存する 3. tobari.CoverWithName(name, entryFunc) API を提供 ◦ アプリ側で、識別子とカバレッジを取りたい関数を指定させる 4. tobari.CoverWithName の entryFunc 呼び出し時の GoroutineID を記録すれば、 GoroutineID ベースでどこを通ったかがわかる tobari.CoverWithName(name, entryFunc) entryFunc ( GID 10 ) foo ( GID 20, PGID: 10 ) bar ( GID 30, PGID: 20 ) GID: Goroutine ID PGID: Parent Goroutine ID
Go Conference mini 2026 in Sendai How to replace go
tool cover ? • Toolexec を利用する ◦ go (build|run|test) などで利用できる option ( -toolexec ) ◦ go tool compile などの tool 呼び出しをフックできる ▪ go build -toolexec=foo ./ • foo compile … or foo link … のような引数で foo が呼ばれる • go tool cover をフックすることもできる ◦ foo cover …
Go Conference mini 2026 in Sendai How to get (
parent ) GoroutineID ? • runtime.getg() で現在の Goroutine 情報がわかる ◦ runtime.getg().goid : GoroutineID ◦ runtime.getg().parentGoid : Parent Goroutine ID • Toolexec を利用して go tool compile の runtime package の compile をフックして以下の内容を加えると動的に公開 APIが作れる package runtime func GID() uint64 { return getg().goid } func PGID() uint64 { return getg().parentGoid }
Go Conference mini 2026 in Sendai Tips: go tool compile
をフックする上での注意
Go Conference mini 2026 in Sendai ビルドキャッシュの分離 • コンパイル時にファイルを置き換える場合、ビルドキャッシュが効くと go
tool compile がそもそも呼ばれないので、キャッシュ管理が必須 • Go コンパイラは各 go tool を呼び出す前に、必ず go tool compile -V=full の ように -V=full 付きのリクエストを行う ◦ -V=full の標準出力の結果を使って Build Cache ID が決まる仕様 ◦ 出力結果を変えるとキャッシュが別になるのでフルビルド ◦ @sivchari さんに教えてもらった • Tobari では、Tobari binary の hash値、置き換え処理で利用するファイルの hash値 などを組み合わせて Build Cache ID を作っている ◦ tobari: <replace-file-hash> exe:<binary-hash>
Go Conference mini 2026 in Sendai 依存パッケージの管理 • 置き換えたファイルが新しい依存を持っている場合、そのパッケージをビルドした上で、 go
tool compile がコンパイルできるように、ビルドしたパッケージへのパスを 教える必要がある • go tool compile には -importcfg import.cfg という option があり、 import.cfg が依存パッ ケージのリスト管理している ◦ packagefile <package-name>=<package-path> の羅列 ◦ -x option をつけてビルドすると簡単に中身が見れる e.g.) go build -x ./ • import.cfg にビルド結果を追記すれば良い • ビルドは go list -deps -export -json <package> を使う ◦ <package> をビルドし、依存 package の path も含めて JSON 形式で取得できる
Go Conference mini 2026 in Sendai 計測コードの挿入時の課題 • go tool
cover に代わって自前のコードを挿入する際、次のようなコードを追加したい ◦ tobari.Trace(runtime.PGID(), runtime.GID(), startLine, startCol, …) • もともとカバレッジ対象の package が runtime や tobari package に 依存していない場合、 import.cfg への追記が必要になり処理が複雑になる package foo import ( “runtime” “github.com/goccy/tobari” ) func Foo() { tobari.Trace(runtime.PGID(), runtime.GID(), 6, 11, …) }
Go Conference mini 2026 in Sendai linkname を利用した依存解決 • linkname
directive を利用することで runtime や github.com/goccy/tobari package を import せずにコンパイルできる • ただし、go tool link 時に指定する import.cfg には必ず runtime や github.com/goccy/tobari への依存が必要なので注意 import _ “unsafe” //go:linkname runtime_GID runtime.GID func runtime_GID() uint64 //go:linkname tobari_Trace github.com/goccy/tobari/internal/tobari.Trace func tobari_Trace(uint64, uint64, int, int, int, int, int, int) func Foo() { tobari_Trace(runtime_PGID(), runtime_GID(), 6, 11, …) }
Go Conference mini 2026 in Sendai 静的解析による到達範囲推定 • go tool
cover で渡されたコードを静的解析し、関数間の依存関係を記録する • Tobari のカバレッジ測定エントリポイントから呼ばれた関数を記録 ◦ tobari.CoverWithName(name, func() { foo() }) • 実際に呼ばれた関数 ( foo )が依存する関数全てを静的解析の結果から導き、 それを通過すべき範囲とする • foo から絶対に呼ばれない関数は、通過すべき範囲に含まれない
Go Conference mini 2026 in Sendai まとめ • Go標準の仕組みの代わりに使えるコードカバレッジ計測ツール、 Tobari
を開発 • GoroutineID を使って、テストごとのカバレッジデータを正確に測定 • Agent Skills などを通して Coding Agent に有益な情報を提供することが目的 • GOFLAGS=$(tobari flags) go test ./ でなぜ測定できるのか ◦ Toolexec の活用 ▪ go tool cover をフックして GoroutineID 付きで計測 ▪ go tool compile をフックしてコンパイル対象を差し替え ◦ linkname を活用しながらカバレッジ計測コードを挿入 ◦ 静的解析を使ってカバー範囲を推定
Go Conference mini 2026 in Sendai
Go Conference mini 2026 in Sendai Appendix
Go Conference mini 2026 in Sendai Coverage Metadata and Countdata
• Go のカバレッジデータは内部的に Metadata と Countdata に分かれている • Metadata ◦ go tool cover を実行した際に作成 ◦ package の名前やファイルパスなど静的に決まる情報を保持 • Countdata ◦ ソースコードの場所に紐づくカウントを保持 • coverprofile 形式で出力する場合は Metadata と Countdata を合成する • go test では、裏で作る testmain.go で合成し、結果を出力
Go Conference mini 2026 in Sendai Overlay • 標準ライブラリのコンパイル対象を変更できる ◦
replace: $GOROOT/src/runtime/stubs.go => /tmp/stubs.go ◦ add: $GOROOT/src/runtime/new.go => /tmp/new.go • Goコンパイラ側が置き換えるべきファイルを解析し、 ビルドキャッシュを使うか判断したり、 package の依存解決も行う • 標準ライブラリにもともと書いてあったかのように振る舞う • $GOMODCACHE 以下のファイルには適用できない ◦ toolchain directive を利用してインストールされる Go は $GOMODCACHE 以下に配 置されるため、置き換えられない ◦ GOTOOLCHAIN=local が必須
Go Conference mini 2026 in Sendai Toolexec Tips: Importcfg •
go tool compile と go tool link で指定される • go tool compile ◦ Signature の Check に利用される ◦ I/F が一緒なら、中身はなんでも良い • go tool link ◦ 依存している package すべての symbol が同じものである必要がある ◦ 例えば異なる Overlay ファイルからビルドされた同じ名前の package が依 存にあると fingerprint mismatch error が発生するので注意
Go Conference mini 2026 in Sendai Toolexec Tips: BuildID •
Toolexec では go tool (compile|cover|vet|link) が別プロセスで起動する が、 go build ごとにユニークな共通のデータにアクセスしたいことがある • go tool の呼び出しは go build の子プロセスになるため、 os.Getppid() を 使うことで go build プロセスの PID を取得できる • go build ごとにユニークな ID として利用できるため、これを使って 一時ディレクトリを作ってリソースを共有することができる go build ( PID: 10 ) go tool compile … (PID: 20, PPID: 10 ) go tool cover … ( PID: 30, PPID: 10 ) go tool link … ( PID: 40: PPID: 10 )
Go Conference mini 2026 in Sendai How to build github.com/goccy/tobari
package ? • github.com/goccy/tobari の package を link 時にビルドするため、 filepath.Join(os.TempDir(), “tobari”, os.Getppid(), “app”) 配下に main.go と go.mod を配置 ◦ main.go: import _ “github.com/goccy/tobari” を追加 ◦ go.mod: require github.com/goccy/tobari <version> を追加 ▪ <version> は Tobari 自身が知っているのがポイント • “app” の下で go list -deps -export -json -toolexec=tobari github.com/goccy/tobari を実行すると build した package への path が手に入る
Go Conference mini 2026 in Sendai テスト実行時のカバレッジ出力方法 GOFLAGS=$(tobari flags) go
test ./… でカバレッジをテスト単位で出力するため、 testing package の関数を置き換えている GS=$(tobari flags) go test ./…FLAGS=$(tobari package testing import _ "unsafe" //go:linkname tobari_cover github.com/goccy/tobari/internal/tobari.Cover func tobari_cover(name, entryID string) func (t *T) Run(name string, f func(*T)) bool { // オリジナルの (*testing.T).Run を呼び出す return t.orgRun(name, func(t *T) { // Test名とGoroutineIDを紐づける tobari_cover(t.Name(), t.Name()) f(t) }) } package testdeps // カバレッジ出力のために呼び出される関数 func coverTearDown( coverprofile string, gocoverdir string, ) (string, error) { // メタデータとカウントデータを設定 // tobari/tobari.json に出力 } testing/internal/testdeps.coverTearDown testing.(*T).Run
Go Conference mini 2026 in Sendai 静的解析時の依存グラフの調整 • 探索範囲を最適化 ◦
runtime, net/http, google.golang.org/grpc に到達したら打ち切る • runtime: GC 関連の API が全関数への依存を持つため無視 • net/http or google.golang.org/grpc: 全ハンドラへの参照を持つため無視
Go Conference mini 2026 in Sendai 埋め込み Option ( –embed-code
) の提供 • go test を利用しないパターンで coverage を取得した場合、 ビルドに利用したソースコードが手元にないことが多い ◦ e.g.) Container Image を作るタイミングでソースコードが消えている • Tobari では、 toolexec の option として —embed-code option をサポート ◦ go tool cover の処理を行う際に引数で渡されたソースコードを埋め込む ◦ tobari.ReadCoverArchivedFile() API を呼び出すと埋め込んだソースコー ドを tar.gz 形式で取得できる • Tobari の HTML 表示コマンドにはソースコードを渡すために tar.gz を渡す option や、ファイルを埋め込んだバイナリ自体を指定する option があり、 それを利用すると簡単に HTML 化ができる
Go Conference mini 2026 in Sendai