golang-testing
本番品質のGolangテストを記述するための包括的なガイドを提供します。テーブル駆動テスト、testifyを使ったテストスイート、モック、ユニット・統合テスト、ベンチマーク、カバレッジ計測、並列テスト、ファジング、フィクスチャ、goleakによるゴルーチンリーク検出、スナップショットテスト、メモリリーク対策、GitHub Actions による CI、慣用的な命名規則などを網羅しています。Goプロジェクトでテストを書く際、テストパターンの調査、または CI のセットアップを行う場面で活用してください。
description の原文を見る
Provides a comprehensive guide for writing production-ready Golang tests. Covers table-driven tests, test suites with testify, mocks, unit tests, integration tests, benchmarks, code coverage, parallel tests, fuzzing, fixtures, goroutine leak detection with goleak, snapshot testing, memory leaks, CI with GitHub Actions, and idiomatic naming conventions. Use this whenever writing tests, asking about testing patterns or setting up CI for Go projects. Essential for ANY test-related conversation in Go.
SKILL.md 本文
ペルソナ: あなたはテストを実行可能な仕様として扱うGoエンジニアです。カバレッジ目標を達成するのではなく、動作を制約するためにテストを書きます。
シンキングモード: テスト戦略の設計と失敗分析には ultrathink を使用します。浅い推論ではエッジケースを見落とし、今日はパスしても明日は壊れるもろいテストが生成されます。
モード:
- 書き込みモード — 既存または新しいコードに対して新しいテストを生成します。テスト対象のコードを順序立てて進め、
gotestsを使用してテーブル駆動テストをスキャフォルディングしてから、エッジケースとエラーパスで充実させます。 - レビューモード — PRのテスト変更をレビューします。差分に焦点を当て、新しい動作のカバレッジ、アサーション品質、テーブル駆動構造、および不安定性パターンの欠如を確認します。順序立てて。
- 監査モード — 既存のテストスイートのギャップ、不安定性、または悪いパターン(順序に依存するテスト、
t.Parallel()の欠落、実装詳細との結合)を監査します。最大3つの並列サブエージェントを懸念別に起動します:(1)ユニットテストの品質とカバレッジギャップ、(2)統合テストの分離とビルドタグ、(3)goroutineリークと競合状態。 - デバッグモード — テストが失敗しているか不安定です。順序立てて進めます:確実に再現し、失敗したアサーションを分離し、本番コードまたはテストセットアップの根本原因をトレースします。
コミュニティデフォルト。
samber/cc-skills-golang@golang-testingスキルを明示的に置き換える企業スキルが優先されます。
Go テストのベストプラクティス
このスキルはGoアプリケーション用の本番対応テストの作成をガイドします。以下の原則に従って、保守性が高く、高速で信頼性の高いテストを書きます。
ベストプラクティス概要
- テーブル駆動テストは名前付きサブテストを使用する必要があります -- 各テストケースは
t.Runに渡されるnameフィールドが必要です - 統合テストはビルドタグ(
//go:build integration)を使用してユニットテストから分離する必要があります - テストは実行順序に依存してはいけません -- 各テストは独立して実行可能でなければなりません
- 独立したテストは可能な限り
t.Parallel()を使用すべきです - 実装詳細をテストしないでください -- 観察可能な動作とパブリックAPI契約をテストしてください
- goroutineを含むパッケージは
TestMainでgoleak.VerifyTestMainを使用してgoroutineリークを検出すべきです - testifyをヘルパーとして使用し、標準ライブラリの置き換えとしては使用しないでください
- 具体的な型ではなく、インターフェースをモックします
- ユニットテストは高速に保つ(< 1ms)、統合テストにはビルドタグを使用します
- CI でレース検出でテストを実行します
- 例を実行可能なドキュメントとして含めます
テスト構造と組織
ファイル規則
// package_test.go - 同じパッケージ内のテスト(ホワイトボックス、エクスポートされていないコードにアクセス可能)
package mypackage
// mypackage_test.go - テストパッケージ内のテスト(ブラックボックス、パブリックAPIのみ)
package mypackage_test
命名規則
func TestAdd(t *testing.T) { ... } // 関数テスト
func TestMyStruct_MyMethod(t *testing.T) { ... } // メソッドテスト
func BenchmarkAdd(b *testing.B) { ... } // ベンチマーク
func ExampleAdd() { ... } // 例
func FuzzAdd(f *testing.F) { ... } // ファジングテスト
テーブル駆動テスト
テーブル駆動テストはGoで複数のシナリオをテストするための慣用的な方法です。常に各テストケースに名前を付けてください。
func TestCalculatePrice(t *testing.T) {
tests := []struct {
name string
quantity int
unitPrice float64
expected float64
}{
{
name: "single item",
quantity: 1,
unitPrice: 10.0,
expected: 10.0,
},
{
name: "bulk discount - 100 items",
quantity: 100,
unitPrice: 10.0,
expected: 900.0, // 10% discount
},
{
name: "zero quantity",
quantity: 0,
unitPrice: 10.0,
expected: 0.0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := CalculatePrice(tt.quantity, tt.unitPrice)
if got != tt.expected {
t.Errorf("CalculatePrice(%d, %.2f) = %.2f, want %.2f",
tt.quantity, tt.unitPrice, got, tt.expected)
}
})
}
}
ユニットテスト
ユニットテストは高速(< 1ms)で、分離された(外部依存なし)で、決定的であるべきです。
HTTPハンドラーのテスト
HTTPハンドラーテストには httptest を使用し、テーブル駆動パターンで使用します。リクエスト/レスポンスボディ、クエリパラメータ、ヘッダー、ステータスコードアサーションの例については、HTTP Testing を参照してください。
goleakを使用したgoroutineリーク検出
特に並行コードの場合、go.uber.org/goleak を使用してリークするgoroutineを検出します:
import (
"testing"
"go.uber.org/goleak"
)
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
}
特定のgoroutineスタックを除外する(既知のリークまたはライブラリgoroutineの場合):
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m,
goleak.IgnoreCurrent(),
)
}
またはテストごと:
func TestWorkerPool(t *testing.T) {
defer goleak.VerifyNone(t)
// ... test code ...
}
testing/synctest による決定的なgoroutineテスト
実験的:
testing/synctestはまだGoの互換性保証に含まれていません。将来のリリースでAPIが変わる可能性があります。安定した代替案については、clockworkを使用します(Mockingを参照)。
testing/synctest(Go 1.24+)は並行コードテストのための決定的な時間を提供します。すべてのgoroutineがブロックされている場合のみ時間が進むため、順序が予測可能になります。
synctest を実時間の代わりに使用する場合:
- 時間ベースの操作(time.Sleep、time.After、time.Ticker)を使用した並行コードのテスト
- 競合状態を再現可能にする必要がある場合
- タイミングの問題により、テストが不安定な場合
import (
"testing"
"time"
"testing/synctest"
"github.com/stretchr/testify/assert"
)
func TestChannelTimeout(t *testing.T) {
synctest.Run(func(t *testing.T) {
is := assert.New(t)
ch := make(chan int, 1)
go func() {
time.Sleep(50 * time.Millisecond)
ch <- 42
}()
select {
case v := <-ch:
is.Equal(42, v)
case <-time.After(100 * time.Millisecond):
t.Fatal("timeout occurred")
}
})
}
synctest の主な違い:
time.Sleepはgoroutineがブロックされると合成時間を即座に進めますtime.Afterは合成時間が期間に到達するとトリガーされます- すべてのgoroutineはタイムが進む前にブロッキングポイントまで実行されます
- テスト実行は決定的で反復可能です
テストタイムアウト
ハングする可能性があるテストについては、呼び出し元の位置でパニックになるタイムアウトヘルパーを使用します。Helpers を参照してください。
ベンチマーク
→ 詳細なベンチマークについては samber/cc-skills-golang@golang-benchmark スキルを参照してください:b.Loop()(Go 1.24+)、benchstat、ベンチマークからのプロファイリング、およびCI回帰検出。
パフォーマンスを測定し、回帰を検出するためにベンチマークを書きます:
func BenchmarkStringConcatenation(b *testing.B) {
b.Run("plus-operator", func(b *testing.B) {
for i := 0; i < b.N; i++ {
result := "a" + "b" + "c"
_ = result
}
})
b.Run("strings.Builder", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var builder strings.Builder
builder.WriteString("a")
builder.WriteString("b")
builder.WriteString("c")
_ = builder.String()
}
})
}
異なる入力サイズを持つベンチマーク:
func BenchmarkFibonacci(b *testing.B) {
sizes := []int{10, 20, 30}
for _, size := range sizes {
b.Run(fmt.Sprintf("n=%d", size), func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
Fibonacci(size)
}
})
}
}
並列テスト
t.Parallel() を使用してテストを並行実行します:
func TestParallelOperations(t *testing.T) {
tests := []struct {
name string
data []byte
}{
{"small data", make([]byte, 1024)},
{"medium data", make([]byte, 1024*1024)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
is := assert.New(t)
result := Process(tt.data)
is.NotNil(result)
})
}
}
ファジング
ファジングを使用してエッジケースとバグを見つけます:
func FuzzReverse(f *testing.F) {
f.Add("hello")
f.Add("")
f.Add("a")
f.Fuzz(func(t *testing.T, input string) {
reversed := Reverse(input)
doubleReversed := Reverse(reversed)
if input != doubleReversed {
t.Errorf("Reverse(Reverse(%q)) = %q, want %q", input, doubleReversed, input)
}
})
}
ドキュメントとしての例
例は go test によって検証される実行可能なドキュメントです:
func ExampleCalculatePrice() {
price := CalculatePrice(100, 10.0)
fmt.Printf("Price: %.2f\n", price)
// Output: Price: 900.00
}
func ExampleCalculatePrice_singleItem() {
price := CalculatePrice(1, 25.50)
fmt.Printf("Price: %.2f\n", price)
// Output: Price: 25.50
}
コードカバレッジ
# カバレッジファイルを生成
go test -coverprofile=coverage.out ./...
# HTMLでカバレッジを表示
go tool cover -html=coverage.out
# 関数別のカバレッジ
go tool cover -func=coverage.out
# 総カバレッジ率
go tool cover -func=coverage.out | grep total
統合テスト
統合テストをユニットテストから分離するためにビルドタグを使用します:
//go:build integration
package mypackage
func TestDatabaseIntegration(t *testing.T) {
db, err := sql.Open("postgres", os.Getenv("DATABASE_URL"))
if err != nil {
t.Fatal(err)
}
defer db.Close()
// 実際のデータベース操作をテスト
}
統合テストを別途実行します:
go test -tags=integration ./...
Docker Composeフィクスチャ、SQLスキーマ、および統合テストスイートについては、Integration Testing を参照してください。
モック
具体的な型ではなく、インターフェースをモックします。使用される場所でインターフェースを定義し、モック実装を作成します。
モックパターン、テストフィクスチャ、および時間モックについては、Mocking を参照してください。
リンターで強制する
多くのテストベストプラクティスはリンターによって自動的に強制されます:thelper、paralleltest、testifylint。設定と使用方法については、samber/cc-skills-golang@golang-lint スキルを参照してください。
クロスリファレンス
- →
samber/cc-skills-golang@golang-stretchr-testifyスキルの詳細なtestify API(assert、require、mock、suite)を参照してください - →
samber/cc-skills-golang@golang-databaseスキル(testing.md)のデータベース統合テストパターンを参照してください - →
samber/cc-skills-golang@golang-concurrencyスキルのgoleakを使用したgoroutineリーク検出を参照してください - →
samber/cc-skills-golang@golang-continuous-integrationスキルのCI テスト設定と GitHub Actions ワークフローを参照してください - →
samber/cc-skills-golang@golang-lintスキルの testifylint と paralleltest 設定を参照してください - →
samber/cc-skills-golang@golang-continuous-integrationスキルのこれらのガイドラインを使用した CI での自動AIドリブンコードレビューを参照してください
クイックリファレンス
go test ./... # すべてのテスト
go test -run TestName ./... # 正確な名前で特定のテスト
go test -run TestName/subtest ./... # テスト内のサブテスト
go test -run 'Test(Add|Sub)' ./... # 複数のテスト(regexp OR)
go test -run 'Test[A-Z]' ./... # 大文字で始まるテスト
go test -run 'TestUser.*' ./... # プレフィックスマッチングテスト
go test -run '.*Validation.*' ./... # 部分文字列を含むテスト
go test -run TestName/. ./... # TestNameのすべてのサブテスト
go test -run '/(unit|integration)' ./... # サブテスト名でフィルタリング
go test -race ./... # 競合検出
go test -cover ./... # カバレッジサマリー
go test -bench=. -benchmem ./... # ベンチマーク
go test -fuzz=FuzzName ./... # ファジング
go test -tags=integration ./... # 統合テスト
ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ
詳細情報
- 作者
- samber
- ライセンス
- MIT
- 最終更新
- 不明
Source: https://github.com/samber/cc-skills-golang / ライセンス: MIT
関連スキル
superpowers-streamer-cli
SuperPowers デスクトップストリーマーの npm パッケージをインストール、ログイン、実行、トラブルシューティングできます。ユーザーが npm から `superpowers-ai` をセットアップしたい場合、メールまたは電話でサインインもしくはアカウント作成を行いたい場合、ストリーマーを起動したい場合、表示されたコントロールリンクを開きたい場合、後で停止したい場合、またはソースコードへのアクセスなしに npm やランタイムの一般的な問題から復旧したい場合に使用します。
catc-client-ops
Catalyst Centerのクライアント操作・監視機能 - 有線・無線クライアントのリスト表示・フィルタリング、MACアドレスによる詳細なクライアント検索、クライアント数分析、時間軸での分析、SSIDおよび周波数帯によるフィルタリング、無線トラブルシューティング機能を提供します。MACアドレスやIPアドレスでのクライアント検索、サイト別やSSID別のクライアント数集計、無線周波数帯の分布分析、Wi-Fi信号の問題調査が必要な場合に活用できます。
ci-cd-and-automation
CI/CDパイプラインの設定を自動化します。ビルドおよびデプロイメントパイプラインの構築または変更時に使用できます。品質ゲートの自動化、CI内のテストランナー設定、またはデプロイメント戦略の確立が必要な場合に活用します。
shipping-and-launch
本番環境へのリリース準備を行います。本番環境へのデプロイ準備が必要な場合、リリース前チェックリストが必要な場合、監視機能の設定を行う場合、段階的なロールアウトを計画する場合、またはロールバック戦略が必要な場合に使用します。
linear-release-setup
Linear Releaseに向けたCI/CD設定を生成します。リリース追跡の設定、LinearのCIパイプライン構築、またはLinearリリースとのデプロイメント連携を実施する際に利用できます。GitHub Actions、GitLab CI、CircleCIなど複数のプラットフォームに対応しています。
tracking-application-response-times
API エンドポイント、データベースクエリ、サービスコール全体にわたるアプリケーションのレスポンスタイムを追跡・最適化できます。パフォーマンス監視やボトルネック特定の際に活用してください。「レスポンスタイムを追跡する」「API パフォーマンスを監視する」「遅延を分析する」といった表現で呼び出せます。