Skip to main content

golang-testing

Go testing standards: table-driven tests, testify, mockgen, coverage measurement, race-safe tests, benchmark correctness, and test isolation patterns. Use when writing, reviewing, or running Go tests.

Quellinformationen

Repository
bivex/go-quality-cli-agent
Letzte Quellaktivität
4. März 2026 um 16:52
Erkannte Sprache von SKILL.md
Englisch
Sterne
0
Forks
0

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
golang-testing
description
Go testing standards: table-driven tests, testify, mockgen, coverage measurement, race-safe tests, benchmark correctness, and test isolation patterns. Use when writing, reviewing, or running Go tests.
allowed-tools
Bash(go test *), Bash(mockgen *), Bash(go generate *), Bash(go tool cover *), Bash(gotestsum *), Read, Grep, Glob
# Go Testing Standards Tests in Go are first-class code. They live next to the implementation, run fast via `go test`, and the race detector is always available. This skill enforces patterns that make tests readable, reliable, and maintainable. --- ## 1. File & Package Naming ``` mypackage/ ├── service.go # production code — package mypackage ├── service_test.go # white-box tests — package mypackage └── service_ext_test.go # black-box tests — package mypackage_test ``` **Convention:** one `_test.go` file per source file. Black-box tests (`_test` package suffix) test the public API and are preferred for packages with stable interfaces. --- ## 2. Test Naming ```go // Pattern: TestFunctionName_Scenario_ExpectedResult func TestGetUser_ValidID_ReturnsUser(t *testing.T) { ... } func TestGetUser_NotFound_ReturnsErrNotFound(t *testing.T) { ... } func TestGetUser_DBError_WrapsError(t *testing.T) { ... } // Subtests pattern: func TestGetUser(t *testing.T) { t.Run("valid ID returns user", func(t *testing.T) { ... }) t.Run("not found returns ErrNotFound", func(t *testing.T) { ... }) t.Run("DB error is wrapped", func(t *testing.T) { ... }) } ``` --- ## 3. Table-Driven Tests The standard Go pattern for testing multiple scenarios: ```go func TestAdd(t *testing.T) { tests := []struct { name string a, b int expected int }{ {name: "positive numbers", a: 1, b: 2, expected: 3}, {name: "negative numbers", a: -1, b: -2, expected: -3}, {name: "zero", a: 0, b: 0, expected: 0}, } for _, tc := range tests { tc := tc // pre 1.22: capture range variable t.Run(tc.name, func(t *testing.T) { t.Parallel() // safe since tc is captured got := Add(tc.a, tc.b) if got != tc.expected { t.Errorf("Add(%d, %d) = %d, want %d", tc.a, tc.b, got, tc.expected) } }) } } ``` --- ## 4. testify Patterns ```go import ( "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) func TestService(t *testing.T) { // require — stops test on failure (use for setup/preconditions) svc, err := NewService(cfg) require.NoError(t, err) // test stops if service failed to create require.NotNil(t, svc) // assert — continues test on failure (use for assertions) result, err := svc.Process("input") assert.NoError(t, err) assert.Equal(t, "expected", result) assert.Contains(t, result, "partial") // Error type checking _, err = svc.Process("") var ve *ValidationError assert.ErrorAs(t, err, &ve) assert.Equal(t, "input", ve.Field) } ``` **Rule:** use `require` for anything that would make subsequent assertions meaningless. Use `assert` for independent checks. --- ## 5. Mocks with mockgen ```go // In the interface file — add go:generate directive: //go:generate mockgen -destination=mocks/user_repo_mock.go -package=mocks . UserRepository type UserRepository interface { FindByID(ctx context.Context, id string) (*User, error) Save(ctx context.Context, user *User) error } ``` ```bash # Generate all mocks go generate ./... # Or directly: mockgen -destination=mocks/user_repo_mock.go -package=mocks \ github.com/myorg/myproject/internal/user UserRepository ``` ```go // Using the mock in tests: import "github.com/myorg/myproject/internal/user/mocks" func TestService_Process(t *testing.T) { ctrl := gomock.NewController(t) defer ctrl.Finish() repo := mocks.NewMockUserRepository(ctrl) repo.EXPECT(). FindByID(gomock.Any(), "user-123"). Return(&User{ID: "user-123", Name: "Alice"}, nil) svc := NewService(repo) result, err := svc.Process(context.Background(), "user-123") require.NoError(t, err) assert.Equal(t, "Alice", result.Name) } ``` --- ## 6. Test Helpers ```go // t.Helper() — marks function as helper so failures point to caller, not helper func createTestUser(t *testing.T, db *DB, name string) *User { t.Helper() // <- this line user := &User{Name: name} require.NoError(t, db.Save(user)) return user } // t.Cleanup() — runs after test (even on failure), replaces defer func TestWithDB(t *testing.T) { db := connectTestDB(t) t.Cleanup(func() { db.Close() }) // no need for defer db.Close() } // t.TempDir() — creates temp dir, auto-cleaned after test func TestFileProcessor(t *testing.T) { dir := t.TempDir() // cleaned automatically // write test files to dir } ``` --- ## 7. Coverage Commands ```bash # Запустить тесты с покрытием go test -coverprofile=coverage.out ./... # Покрытие по каждой функции go tool cover -func=coverage.out # Итоговый % покрытия go tool cover -func=coverage.out | tail -1 # HTML-отчёт (открывается в браузере) go tool cover -html=coverage.out -o coverage.html open coverage.html # Проверить конкретный пакет go test -cover ./internal/user/... # Покрытие только определённых пакетов (исключить generated) go test -coverprofile=coverage.out -coverpkg=./internal/... ./... ``` **Thresholds (рекомендуемые):** - Новый код: ≥ 80% - Существующий: ≥ 70% (предупреждение), ≥ 50% (нельзя снижать) - Критические пакеты (auth, payments): ≥ 90% --- ## 8. Race-Safe Tests ```bash # ВСЕГДА запускать с -race в CI go test -race ./... # С -count=1 чтобы избежать кэширования результатов go test -race -count=1 ./... # Параллельные тесты — объявить явно: func TestConcurrent(t *testing.T) { t.Parallel() // тест запускается параллельно — должен быть race-safe ... } ``` --- ## 9. Build Tags for Integration Tests ```go //go:build integration // +build integration package mypackage_test // Запуск: go test -tags=integration ./... // В CI/CD запускать отдельно от unit-tests ``` --- ## 10. Key Commands ```bash # Все тесты с race detector go test -race -count=1 ./... # Конкретный тест по имени go test -run TestGetUser ./internal/user/... # Конкретный subtest go test -run "TestGetUser/not_found" ./internal/user/... # Verbose output go test -v -race ./... # Покрытие + race go test -race -coverprofile=coverage.out ./... && go tool cover -func=coverage.out | tail -1 # Красивый вывод через gotestsum (если установлен) gotestsum --format=testdox ./... ```
Auf GitHub ansehen