Go Redis Client Test Runner
redis/go-redis
Explains how to run go-redis tests: the Docker Compose stack, make targets, focusing a single Ginkgo spec, the e2e suite and the version environment variables.
“テスト駆動開発とGoコードの高品質を保証するための包括的なテスト戦略。”
$ npx skills add affaan-m/ECC --skill golang-testing -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install affaan-m/ECC golang-testing --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .claude/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .claude/skills/golang-testing && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .claude/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testingType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add affaan-m/ECC --skill golang-testing -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install affaan-m/ECC golang-testing --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .agents/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .agents/skills/golang-testing && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .agents/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add affaan-m/ECC --skill golang-testing -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install affaan-m/ECC golang-testing --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .cursor/skills/golang-testing && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .cursor/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/affaan-m/ECC.git --path docs/ja-JP/skills/golang-testing--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add affaan-m/ECC --skill golang-testing -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install affaan-m/ECC golang-testing --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .gemini/skills/golang-testing && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .gemini/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install affaan-m/ECC golang-testingInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add affaan-m/ECC --skill golang-testing -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .github/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .github/skills/golang-testing && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .github/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add affaan-m/ECC --skill golang-testing -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install affaan-m/ECC golang-testing --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/affaan-m/ECC.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/docs/ja-JP/skills/golang-testing .opencode/skills/golang-testing && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "golang-testing" agent skill from https://github.com/affaan-m/ECC/tree/main/docs/ja-JP/skills/golang-testing into .opencode/skills/golang-testing/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "golang-testing", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
golang-testingGolang Testing is a skill in affaan-m/ECC (276k stars). Its SKILL.md is about 4.5k tokens, and copies of it appear in 2 other owners' repositories. Licence: MIT.
3 steps, taken from the step headings in SKILL.md.
Read from SKILL.md and the folder at commit 4eb71d9. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Shell commands in SKILL.md call:
goFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
POSTGRES_PASSWORDFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
Golang Testing loads about 4.5k tokens when it runs. Until then it costs about 13 tokens; SKILL.md has 105 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.
The full file from affaan-m/ECC at commit 4eb71d9, republished under its MIT licence (© affaan-m). 105 words, ~4,526 tokens.
.claude/skills/golang-testing/SKILL.md (or your agent's skills folder).テスト駆動開発(TDD)とGoコードの高品質を保証するための包括的なテスト戦略。
失敗するテストを書き、実装し、リファクタリングするサイクルに従います。
// 1. テストを書く(失敗)
func TestCalculateTotal(t *testing.T) {
total := CalculateTotal([]float64{10.0, 20.0, 30.0})
want := 60.0
if total != want {
t.Errorf("got %f, want %f", total, want)
}
}
// 2. 実装する(テストを通す)
func CalculateTotal(prices []float64) float64 {
var total float64
for _, price := range prices {
total += price
}
return total
}
// 3. リファクタリング
// テストを壊さずにコードを改善複数のケースを体系的にテストします。
func TestAdd(t *testing.T) {
tests := []struct {
name string
a, b int
want int
}{
{"positive numbers", 2, 3, 5},
{"negative numbers", -2, -3, -5},
{"mixed signs", -2, 3, 1},
{"zeros", 0, 0, 0},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := Add(tt.a, tt.b)
if got != tt.want {
t.Errorf("Add(%d, %d) = %d; want %d",
tt.a, tt.b, got, tt.want)
}
})
}
}サブテストを使用した論理的なテストの構成。
func TestUser(t *testing.T) {
t.Run("validation", func(t *testing.T) {
t.Run("empty email", func(t *testing.T) {
user := User{Email: ""}
if err := user.Validate(); err == nil {
t.Error("expected validation error")
}
})
t.Run("valid email", func(t *testing.T) {
user := User{Email: "test@example.com"}
if err := user.Validate(); err != nil {
t.Errorf("unexpected error: %v", err)
}
})
})
t.Run("serialization", func(t *testing.T) {
// 別のテストグループ
})
}mypackage/
├── user.go
├── user_test.go # ユニットテスト
├── integration_test.go # 統合テスト
├── testdata/ # テストフィクスチャ
│ ├── valid_user.json
│ └── invalid_user.json
└── export_test.go # 内部テスト用の非公開エクスポート// user_test.go - 同じパッケージ(ホワイトボックステスト)
package user
func TestInternalFunction(t *testing.T) {
// 内部をテストできる
}
// user_external_test.go - 外部パッケージ(ブラックボックステスト)
package user_test
import "myapp/user"
func TestPublicAPI(t *testing.T) {
// 公開APIのみをテスト
}func TestBasicAssertions(t *testing.T) {
// 等価性
got := Calculate()
want := 42
if got != want {
t.Errorf("got %d, want %d", got, want)
}
// エラーチェック
_, err := Process()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
// nil チェック
result := GetResult()
if result == nil {
t.Fatal("expected non-nil result")
}
}// ヘルパーとしてマーク(スタックトレースに表示されない)
func assertEqual(t *testing.T, got, want interface{}) {
t.Helper()
if got != want {
t.Errorf("got %v, want %v", got, want)
}
}
func assertNoError(t *testing.T, err error) {
t.Helper()
if err != nil {
t.Fatalf("unexpected error: %v", err)
}
}
// 使用例
func TestWithHelpers(t *testing.T) {
result, err := Process()
assertNoError(t, err)
assertEqual(t, result.Status, "success")
}import "reflect"
func assertDeepEqual(t *testing.T, got, want interface{}) {
t.Helper()
if !reflect.DeepEqual(got, want) {
t.Errorf("got %+v, want %+v", got, want)
}
}
func TestStructEquality(t *testing.T) {
got := User{Name: "Alice", Age: 30}
want := User{Name: "Alice", Age: 30}
assertDeepEqual(t, got, want)
}// 本番コード
type UserStore interface {
GetUser(id string) (*User, error)
SaveUser(user *User) error
}
type UserService struct {
store UserStore
}
// テストコード
type MockUserStore struct {
users map[string]*User
err error
}
func (m *MockUserStore) GetUser(id string) (*User, error) {
if m.err != nil {
return nil, m.err
}
return m.users[id], nil
}
func (m *MockUserStore) SaveUser(user *User) error {
if m.err != nil {
return m.err
}
m.users[user.ID] = user
return nil
}
// テスト
func TestUserService(t *testing.T) {
mock := &MockUserStore{
users: make(map[string]*User),
}
service := &UserService{store: mock}
// サービスをテスト...
}// プロダクションコード - 時間を注入可能にする
type TimeProvider interface {
Now() time.Time
}
type RealTime struct{}
func (RealTime) Now() time.Time {
return time.Now()
}
type Service struct {
time TimeProvider
}
// テストコード
type MockTime struct {
current time.Time
}
func (m MockTime) Now() time.Time {
return m.current
}
func TestTimeDependent(t *testing.T) {
mockTime := MockTime{
current: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC),
}
service := &Service{time: mockTime}
// 固定時間でテスト...
}type HTTPClient interface {
Do(req *http.Request) (*http.Response, error)
}
type MockHTTPClient struct {
response *http.Response
err error
}
func (m *MockHTTPClient) Do(req *http.Request) (*http.Response, error) {
return m.response, m.err
}
func TestAPICall(t *testing.T) {
mockClient := &MockHTTPClient{
response: &http.Response{
StatusCode: 200,
Body: io.NopCloser(strings.NewReader(`{"status":"ok"}`)),
},
}
api := &APIClient{client: mockClient}
// APIクライアントをテスト...
}func TestHandler(t *testing.T) {
handler := http.HandlerFunc(MyHandler)
req := httptest.NewRequest("GET", "/users/123", nil)
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
// ステータスコードをチェック
if rec.Code != http.StatusOK {
t.Errorf("got status %d, want %d", rec.Code, http.StatusOK)
}
// レスポンスボディをチェック
var response map[string]interface{}
if err := json.NewDecoder(rec.Body).Decode(&response); err != nil {
t.Fatalf("failed to decode response: %v", err)
}
if response["id"] != "123" {
t.Errorf("got id %v, want 123", response["id"])
}
}func TestAuthMiddleware(t *testing.T) {
// ダミーハンドラー
nextHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
})
// ミドルウェアでラップ
handler := AuthMiddleware(nextHandler)
tests := []struct {
name string
token string
wantStatus int
}{
{"valid token", "valid-token", http.StatusOK},
{"invalid token", "invalid", http.StatusUnauthorized},
{"no token", "", http.StatusUnauthorized},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
req := httptest.NewRequest("GET", "/", nil)
if tt.token != "" {
req.Header.Set("Authorization", "Bearer "+tt.token)
}
rec := httptest.NewRecorder()
handler.ServeHTTP(rec, req)
if rec.Code != tt.wantStatus {
t.Errorf("got status %d, want %d", rec.Code, tt.wantStatus)
}
})
}
}func TestAPIIntegration(t *testing.T) {
// テストサーバーを作成
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(map[string]string{
"message": "hello",
})
}))
defer server.Close()
// 実際のHTTPリクエストを行う
resp, err := http.Get(server.URL)
if err != nil {
t.Fatalf("request failed: %v", err)
}
defer resp.Body.Close()
// レスポンスを検証
var result map[string]string
json.NewDecoder(resp.Body).Decode(&result)
if result["message"] != "hello" {
t.Errorf("got %s, want hello", result["message"])
}
}func TestUserRepository(t *testing.T) {
db := setupTestDB(t)
defer db.Close()
tests := []struct {
name string
fn func(*testing.T, *sql.DB)
}{
{"create user", testCreateUser},
{"find user", testFindUser},
{"update user", testUpdateUser},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tx, err := db.Begin()
if err != nil {
t.Fatal(err)
}
defer tx.Rollback() // テスト後にロールバック
tt.fn(t, tx)
})
}
}func setupTestDB(t *testing.T) *sql.DB {
t.Helper()
db, err := sql.Open("postgres", "postgres://localhost/test")
if err != nil {
t.Fatalf("failed to connect: %v", err)
}
// スキーマを移行
if err := runMigrations(db); err != nil {
t.Fatalf("migrations failed: %v", err)
}
return db
}
func seedTestData(t *testing.T, db *sql.DB) {
t.Helper()
fixtures := []string{
`INSERT INTO users (id, email) VALUES ('1', 'test@example.com')`,
`INSERT INTO posts (id, user_id, title) VALUES ('1', '1', 'Test Post')`,
}
for _, query := range fixtures {
if _, err := db.Exec(query); err != nil {
t.Fatalf("failed to seed data: %v", err)
}
}
}func BenchmarkCalculation(b *testing.B) {
for i := 0; i < b.N; i++ {
Calculate(100)
}
}
// メモリ割り当てを報告
func BenchmarkWithAllocs(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
ProcessData([]byte("test data"))
}
}func BenchmarkEncoding(b *testing.B) {
data := generateTestData()
b.Run("json", func(b *testing.B) {
b.ReportAllocs()
for i := 0; i < b.N; i++ {
json.Marshal(data)
}
})
b.Run("gob", func(b *testing.B) {
b.ReportAllocs()
var buf bytes.Buffer
enc := gob.NewEncoder(&buf)
b.ResetTimer()
for i := 0; i < b.N; i++ {
enc.Encode(data)
buf.Reset()
}
})
}// 実行: go test -bench=. -benchmem
func BenchmarkStringConcat(b *testing.B) {
b.Run("operator", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = "hello" + " " + "world"
}
})
b.Run("fmt.Sprintf", func(b *testing.B) {
for i := 0; i < b.N; i++ {
_ = fmt.Sprintf("%s %s", "hello", "world")
}
})
b.Run("strings.Builder", func(b *testing.B) {
for i := 0; i < b.N; i++ {
var sb strings.Builder
sb.WriteString("hello")
sb.WriteString(" ")
sb.WriteString("world")
_ = sb.String()
}
})
}func FuzzParseInput(f *testing.F) {
// シードコーパス
f.Add("hello")
f.Add("world")
f.Add("123")
f.Fuzz(func(t *testing.T, input string) {
// パースがパニックしないことを確認
result, err := ParseInput(input)
// エラーがあっても、nilでないか一貫性があることを確認
if err == nil && result == nil {
t.Error("got nil result with no error")
}
})
}func FuzzJSONParsing(f *testing.F) {
f.Add([]byte(`{"name":"test","age":30}`))
f.Add([]byte(`{"name":"","age":0}`))
f.Fuzz(func(t *testing.T, data []byte) {
var user User
err := json.Unmarshal(data, &user)
// JSONがデコードされる場合、再度エンコードできるべき
if err == nil {
_, err := json.Marshal(user)
if err != nil {
t.Errorf("marshal failed after successful unmarshal: %v", err)
}
}
})
}# カバレッジを実行してHTMLレポートを生成
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out -o coverage.html
# パッケージごとのカバレッジを表示
go test -cover ./...
# 詳細なカバレッジ
go test -coverprofile=coverage.out -covermode=atomic ./...// Good: テスタブルなコード
func ProcessData(data []byte) (Result, error) {
if len(data) == 0 {
return Result{}, ErrEmptyData
}
// 各分岐をテスト可能
if isValid(data) {
return parseValid(data)
}
return parseInvalid(data)
}
// 対応するテストが全分岐をカバー
func TestProcessData(t *testing.T) {
tests := []struct {
name string
data []byte
wantErr bool
}{
{"empty data", []byte{}, true},
{"valid data", []byte("valid"), false},
{"invalid data", []byte("invalid"), false},
}
// ...
}//go:build integration
// +build integration
package myapp_test
import "testing"
func TestDatabaseIntegration(t *testing.T) {
// 実際のDBを必要とするテスト
}# 統合テストを実行
go test -tags=integration ./...
# 統合テストを除外
go test ./...import "github.com/testcontainers/testcontainers-go"
func setupPostgres(t *testing.T) *sql.DB {
ctx := context.Background()
req := testcontainers.ContainerRequest{
Image: "postgres:15",
ExposedPorts: []string{"5432/tcp"},
Env: map[string]string{
"POSTGRES_PASSWORD": "test",
"POSTGRES_DB": "testdb",
},
}
container, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
ContainerRequest: req,
Started: true,
})
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() {
container.Terminate(ctx)
})
// コンテナに接続
// ...
return db
}func TestParallel(t *testing.T) {
tests := []struct {
name string
fn func(*testing.T)
}{
{"test1", testCase1},
{"test2", testCase2},
{"test3", testCase3},
}
for _, tt := range tests {
tt := tt // ループ変数をキャプチャ
t.Run(tt.name, func(t *testing.T) {
t.Parallel() // このテストを並列実行
tt.fn(t)
})
}
}func TestWithResourceLimit(t *testing.T) {
// 同時に5つのテストのみ
sem := make(chan struct{}, 5)
tests := generateManyTests()
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
sem <- struct{}{} // 獲得
defer func() { <-sem }() // 解放
tt.fn(t)
})
}
}# 基本テスト
go test ./...
go test -v ./... # 詳細出力
go test -run TestSpecific ./... # 特定のテストを実行
# カバレッジ
go test -cover ./...
go test -coverprofile=coverage.out ./...
# レースコンディション
go test -race ./...
# ベンチマーク
go test -bench=. ./...
go test -bench=. -benchmem ./...
go test -bench=. -cpuprofile=cpu.prof ./...
# ファジング
go test -fuzz=FuzzTest
# 統合テスト
go test -tags=integration ./...
# JSONフォーマット(CI統合用)
go test -json ./...# テストタイムアウト
go test -timeout 30s ./...
# 短時間テスト(長時間テストをスキップ)
go test -short ./...
# ビルドキャッシュのクリア
go clean -testcache
go test ./...// Good: テーブル駆動テストで繰り返しを削減
func TestValidation(t *testing.T) {
tests := []struct {
input string
valid bool
}{
{"valid@email.com", true},
{"invalid-email", false},
{"", false},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
err := Validate(tt.input)
if (err == nil) != tt.valid {
t.Errorf("Validate(%q) error = %v, want valid = %v",
tt.input, err, tt.valid)
}
})
}
}// Good: テストデータを testdata/ ディレクトリに配置
func TestLoadConfig(t *testing.T) {
data, err := os.ReadFile("testdata/config.json")
if err != nil {
t.Fatal(err)
}
config, err := ParseConfig(data)
// ...
}func TestWithCleanup(t *testing.T) {
// リソースを設定
file, err := os.CreateTemp("", "test")
if err != nil {
t.Fatal(err)
}
// クリーンアップを登録(deferに似ているが、サブテストで動作)
t.Cleanup(func() {
os.Remove(file.Name())
})
// テストを続ける...
}// Bad: 不明確なエラー
if result != expected {
t.Error("wrong result")
}
// Good: コンテキスト付きエラー
if result != expected {
t.Errorf("Calculate(%d) = %d; want %d", input, result, expected)
}
// Better: ヘルパー関数の使用
assertEqual(t, result, expected, "Calculate(%d)", input)// Bad: 外部状態に依存
func TestBadDependency(t *testing.T) {
result := GetUserFromDatabase("123") // 実際のDBを使用
// テストが壊れやすく遅い
}
// Good: 依存を注入
func TestGoodDependency(t *testing.T) {
mockDB := &MockDatabase{
users: map[string]User{"123": {ID: "123"}},
}
result := GetUser(mockDB, "123")
}
// Bad: テスト間で状態を共有
var sharedCounter int
func TestShared1(t *testing.T) {
sharedCounter++
// テストの順序に依存
}
// Good: 各テストを独立させる
func TestIndependent(t *testing.T) {
counter := 0
counter++
// 他のテストに影響しない
}
// Bad: エラーを無視
func TestIgnoreError(t *testing.T) {
result, _ := Process()
if result != expected {
t.Error("wrong result")
}
}
// Good: エラーをチェック
func TestCheckError(t *testing.T) {
result, err := Process()
if err != nil {
t.Fatalf("Process() error = %v", err)
}
if result != expected {
t.Errorf("got %v, want %v", result, expected)
}
}| コマンド/パターン | 目的 |
|---|---|
go test ./... | すべてのテストを実行 |
go test -v | 詳細出力 |
go test -cover | カバレッジレポート |
go test -race | レースコンディション検出 |
go test -bench=. | ベンチマークを実行 |
t.Run() | サブテスト |
t.Helper() | テストヘルパー関数 |
t.Parallel() | テストを並列実行 |
t.Cleanup() | クリーンアップを登録 |
testdata/ | テストフィクスチャ用ディレクトリ |
-short | 長時間テストをスキップ |
-tags=integration | ビルドタグでテストを実行 |
覚えておいてください: 良いテストは高速で、信頼性があり、保守可能で、明確です。複雑さより明確さを目指してください。
© affaan-m, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
Just SKILL.md in docs/ja-JP/skills/golang-testing of affaan-m/ECC.
Open the folder on GitHubat commit 4eb71d9
We found 2 copies of this SKILL.md (exact, near-identical or edited) in other folders, from 2 other GitHub owners. This page covers the copy in affaan-m/ECC, which our catalogue first saw on October 7, 2026.
Golang Testing next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| Golang Testing this skillaffaan-m/ECC | 276k | 2 repos | ~4.5k | Automated safety check: Pass | MIT | |
| Go Redis Client Test Runnerredis/go-redis | 22k | — | ~786 | Automated safety check: Pass | BSD-2-Clause | |
| Golang Testingantoniopaya22/go-rest-template | 172 | 9 repos | ~4.2k | Automated safety check: Pass | None | |
| UI Previewtingly-dev/tingly-box | 351 | — | ~2k | Automated safety check: Notes | MPL-2.0 | |
| NIC Testing Patternsnginx/kubernetes-ingress | 5.1k | — | ~2.8k | Automated safety check: Pass | Apache-2.0 | |
| Writing gotest Testsmvrahden/go-test | 128 | — | ~3.1k | Automated safety check: Pass | MIT |
redis/go-redis
Explains how to run go-redis tests: the Docker Compose stack, make targets, focusing a single Ginkgo spec, the e2e suite and the version environment variables.
antoniopaya22/go-rest-template
Go testing patterns including table-driven tests, subtests, benchmarks, fuzzing, and test coverage.
tingly-dev/tingly-box
Capture headless-Chrome screenshots of the tingly-box frontend (running locally in mock mode) so frontend changes can be visually verified in environments without a real browser.
nginx/kubernetes-ingress
Testing conventions for the NGINX Ingress Controller repo: Go table-driven tests, mandatory snapshot regeneration, Helm tests and Python pytest integration tests.
mvrahden/go-test
Guides writing, fixing and migrating tests in Go repositories that use the gotest suite framework, including version differences and CI setup.
SmilyOrg/photofield
Check and apply security updates across the photofield project (api/Go, ui/npm, docs/npm, e2e/npm).
affaan-m/ECC
Audits your installed Claude skills and commands for quality, with a quick mode for recently changed skills and a full mode that evaluates all of them through subagents.
affaan-m/ECC
Ingests, indexes, searches, edits and monitors video, audio and live streams through the VideoDB Python SDK, returning stream links, clips and timestamps.
affaan-m/ECC
Route broad documentation-governance requests to existing ECC skills and run an opt-in, read-only audit of mapped documentation roles, links, ADR indexes, and evidence references.
affaan-m/ECC
Scans installed skills for principles that recur across them and proposes rule-file changes: append, revise, add a section, create a file or leave as covered.
affaan-m/ECC
Builds DRAFT counterparty agreements from one markdown template and a small JSON spec per party, with clauses picked by the party's role.
affaan-m/ECC
Set an ECC-specific frontend design direction for production UI work.
Works with
Categories
Run `npx skills add affaan-m/ECC --skill golang-testing -a claude-code`. Or copy the skill folder (docs/ja-JP/skills/golang-testing in affaan-m/ECC) into .claude/skills/golang-testing in your project. Claude Code loads it when a task matches its description.
Run `npx skills add affaan-m/ECC --skill golang-testing -a codex`. Or copy the skill folder (docs/ja-JP/skills/golang-testing in affaan-m/ECC) into .agents/skills/golang-testing in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add affaan-m/ECC --skill golang-testing -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/golang-testing, .gemini/skills/golang-testing, .github/skills/golang-testing and .opencode/skills/golang-testing in your project.
Going by SKILL.md and its folder, Golang Testing needs the command-line tools its instructions call (go) and credentials named POSTGRES_PASSWORD.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.
Golang Testing is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 4.5k tokens (SKILL.md is roughly 18k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.
Skills that share tags, products or a category with Golang Testing: Go Redis Client Test Runner (redis/go-redis, 22k stars), Golang Testing (antoniopaya22/go-rest-template, 172 stars), UI Preview (tingly-dev/tingly-box, 351 stars) and NIC Testing Patterns (nginx/kubernetes-ingress, 5.1k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
affaan-m (a GitHub user) maintains it in affaan-m/ECC, which has 276,111 GitHub stars. The repository holds 683 skills in this directory. The repository was last updated on October 10, 2026.
Source: affaan-m/ECC on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.