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.

Informações da origem

Repositório
bivex/go-quality-cli-agent
Última atividade na origem
4 de março de 2026 às 16:52
Idioma detectado do SKILL.md
inglês
Estrelas
0
Forks
0

Opções de instalação

Por padrão, está selecionado o prompt que primeiro revisa a origem. Você pode mudar para um comando direto ou baixar uma cópia local.

Revise os arquivos de origem

Leia o SKILL.md e os arquivos complementares exibidos pelo SkillsMP antes de decidir se vai instalar.

Exibindo SKILL.md

SKILL.md
Instruções da origem · Visualização somente leitura
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 ./... ```
Ver no GitHub