К основному содержанию
скилл CX Codex

go-test-quality — скилл для Claude Code: тесты Go и установка

Скилл помогает писать и проверять тесты Go: от выбора подхода до изоляции сценариев и поиска пробелов в покрытии. Пригодится при доработке тестов и разборе нестабильных проверок.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add eduardo-sl/go-agent-skills --skill go-test-quality -a claude-code
Открыть на GitHub

Что делает go-test-quality

Скилл предлагает проверять поведение кода, а не детали его реализации, и группировать сценарии через t.Run. В нём есть рекомендации по тестовым хелперам, фикстурам, golden-файлам и выбору между httptest, testcontainers и fuzz-тестами. Для небольших интерфейсов он советует ручные моки; чистые функции и стандартную библиотеку предлагает тестировать напрямую.

Для оценки покрытия описана команда go test -race -coverprofile=coverage.out -coverpkg=./... ./... и просмотр отчёта через go tool cover -html=coverage.out. Скилл также разбирает параллельные тесты и testing/synctest. Контейнерные интеграционные тесты требуют Docker, а код с привязкой ко времени для synctest рассчитан на Go 1.25+.

Какие задачи решает

  • выбрать тип теста для HTTP-обработчика или базы данных
  • разделить сценарии теста с помощью t.Run
  • подготовить хелперы и очистку ресурсов через t.Cleanup
  • найти непокрытые участки кода в отчёте Go
  • разобрать причины нестабильных тестов с параллельным кодом

Примеры запросов агенту

  • Добавь тесты для этого Go-кода и проверь поведение, а не внутренние вызовы.
  • Посмотри покрытие пакета и предложи сценарии для непроверенных веток.
  • Разбери нестабильный тест с горутинами и подскажи, как синхронизировать его без time.Sleep.

Как установить go-test-quality

1Через Skills CLI (Vercel)

npx skills add eduardo-sl/go-agent-skills --skill go-test-quality -a claude-code

2Вручную: положить файлы

~/.claude/skills/go-test-quality/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/go-test-quality/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о go-test-quality

Как установить go-test-quality в Claude Code?

Выполни npx skills add eduardo-sl/go-agent-skills --skill go-test-quality -a claude-code. Файл скилла будет доступен по пути ~/.claude/skills/go-test-quality/SKILL.md.

Что делает go-test-quality?

Он помогает выбирать подходы к тестированию Go, проектировать сценарии, писать хелперы и моки, анализировать покрытие и проверять конкурентный код.

Что нужно для интеграционных тестов с testcontainers?

Для контейнерных интеграционных тестов нужен Docker. Для тестов кода с зависимостью от времени с помощью testing/synctest требуется Go 1.25+.

Исходный текст

SKILL.md · MIT
---
name: go-test-quality
description: >
  Go testing patterns for production-grade code: subtests, test helpers,
  fixtures, golden files, httptest, testcontainers, fuzz testing, and
  testing/synctest. Covers mocking strategies, test isolation, coverage
  analysis, and test design philosophy. Use when writing tests, improving
  coverage, reviewing test quality, setting up test infrastructure, or
  choosing a testing approach. Trigger examples: "add tests", "improve
  coverage", "write tests for this", "test helpers", "mock this dependency",
  "integration test", "fuzz test", "flaky test", "synctest", "goroutine leak
  in tests".
  Not for: benchmarking methodology (go-performance-review), security
  testing (go-security-audit), table-driven patterns (go-test-table-driven).
user-invocable: true
license: MIT
compatibility: Designed for Claude Code or similar AI coding agents working on Go projects. Requires the Go toolchain. Container-based integration tests require Docker.
allowed-tools: Read Edit Write Glob Grep Bash(go:*) Bash(gofmt:*)
metadata:
  author: eduardo-sl
  version: "1.5.1"
---

# Go Test Quality

Tests are production code. They run in CI on every commit, they document behavior,
and they're the first thing you read when a function breaks at 3am.
Write them with the same care you'd give to code that handles money.

> Community default. A project skill or agent-config rule that explicitly
> supersedes `go-test-quality` takes precedence over this one.

Detailed reference material, loaded on demand:

- `references/helpers-and-fixtures.md` — test helpers, factory functions
  with options, `t.Cleanup`, golden files, mock implementations.
- `references/integration-testing.md` — httptest recorder and server,
  testcontainers, build tags, `TestMain`, fuzz testing.
- `references/concurrency-and-benchmarks.md` — `synctest`, `goleak`,
  `t.Context()`, `b.Loop()` benchmarks, `t.Attr` and artifacts.

Read a reference file only when the summary below is not enough.

## 1. Test Design Philosophy

### Test behavior, not implementation

```go
// ✅ Good — tests what the function DOES
func TestTransferFunds_InsufficientBalance(t *testing.T) {
    from := NewAccount("alice", 100)
    to := NewAccount("bob", 0)

    err := TransferFunds(from, to, 150)

    require.ErrorIs(t, err, ErrInsufficientFunds)
    assert.Equal(t, 100, from.Balance(), "sender balance should be unchanged")
    assert.Equal(t, 0, to.Balance(), "receiver balance should be unchanged")
}

// ❌ Bad — tests HOW the function does it
// asserts debit() was called before credit(), rollback() was called,
// internal mutex was locked — breaks on every refactor
```

### One assertion per logical concept

Multiple `assert` calls are fine when they verify different facets of the
SAME behavior (both accounts after a transfer). A test that checks creation
AND update AND deletion is three tests pretending to be one.

### Name tests like bug reports

When the test fails, the name alone should say what broke:

```go
// ✅ Good — reads like a sentence
func TestOrderService_Cancel_RefundsPartiallyShippedItems(t *testing.T) { ... }
func TestParseConfig_ReturnsErrorOnMissingRequiredField(t *testing.T) { ... }

// ❌ Bad — says nothing useful
func TestCancel(t *testing.T) { ... }
func TestRateLimiter_Success(t *testing.T) { ... }
```

### Layout

- One `_test.go` per source file (`parser.go` → `parser_test.go`), tests
  in the order of the functions they cover — tools and reviewers navigate
  by file.
- Public-API tests live in the `pkg_test` package so they can only use
  what callers can; white-box tests stay in `pkg`.
- Integration tests sit behind `//go:build integration`.

## 2. Subtests for Organized Scenarios

Use `t.Run` to group related scenarios under a parent test. Each subtest
gets its own setup, its own failure, and its own name in CI output:

```go
func TestUserService_Create(t *testing.T) {
    svc := setupUserService(t)

    t.Run("succeeds with valid input", func(t *testing.T) {
        user, err := svc.Create(ctx, CreateUserInput{Name: "Alice", Email: "[email protected]"})
        require.NoError(t, err)
        assert.NotEmpty(t, user.ID)
    })

    t.Run("rejects duplicate email", func(t *testing.T) {
        _, _ = svc.Create(ctx, CreateUserInput{Name: "Alice", Email: "[email protected]"})
        _, err := svc.Create(ctx, CreateUserInput{Name: "Bob", Email: "[email protected]"})
        require.ErrorIs(t, err, ErrDuplicateEmail)
    })
}
```

## 3. Test Helper Rules

1. **Always call `t.Helper()`** in test utilities so failures point to the
   caller, not the helper.
2. **Factory functions with functional options** for complex test objects —
   defaults with per-test overrides, never a 15-parameter constructor.
3. **Prefer `t.Cleanup` over `defer`** — it runs even after `t.FailNow()`
   and is scoped to the test, not the function.

Full implementations in `references/helpers-and-fixtures.md`.

## 4. Choosing the Test Type

| Situation | Approach | Details |
|---|---|---|
| Pure function, 3+ data cases | Table-driven test | go-test-table-driven skill |
| HTTP handler in isolation | `httptest.NewRecorder` + mock store | `references/integration-testing.md` |
| Full routing/middleware stack | `httptest.NewServer` | `references/integration-testing.md` |
| Real database behavior | testcontainers + build tags | `references/integration-testing.md` |
| Complex output (JSON, HTML, SQL) | Golden files in `testdata/` | `references/helpers-and-fixtures.md` |
| Parser/validator on untrusted input | Fuzz test | `references/integration-testing.md` |

## 5. Mocking Rules

- **Interface-based hand-written mocks** for small interfaces (≤3 methods):
  a struct with function fields plus recorded calls.
- **Function injection** for simple seams (`now func() time.Time`).
- **Do NOT mock:** value objects, pure functions, the standard library, or
  your own code in the same package. Test the real thing.
- If you mock everything, you're testing your mocks, not your code.

## 6. Parallelism and Coverage

```go
func TestSlugify(t *testing.T) {
    t.Parallel() // safe: pure function, no shared state
    // ...
}
```

Do NOT use `t.Parallel()` when tests share mutable state, databases,
files, or process-level state — `t.Setenv` and `t.Chdir` panic in a
parallel test for exactly that reason.

```bash
go test -race -coverprofile=coverage.out -coverpkg=./... ./...
go tool cover -html=coverage.out   # read the red lines, not the percentage
```

Coverage finds untested code; it does not measure whether the assertions
are any good. Use it to locate gaps, and let CI enforce a floor that only
ratchets up (the go-ci skill owns the gate). Without `-coverpkg`, a
package exercised only by another package's tests reports 0%.

## 7. Testing Concurrent Code

- Never synchronise a test with `time.Sleep` — it is slow when it works and
  flaky when it does not.
- Go 1.25+: run time-dependent code inside `synctest.Test`. The bubble's
  fake clock advances instantly once every goroutine is blocked, and
  `synctest.Wait()` replaces "sleep until the background goroutine gets
  there". On Go 1.24 the API is `synctest.Run` behind
  `GOEXPERIMENT=synctest`. Go 1.27 adds `synctest.Sleep(d)` (advance and
  settle in one call) and `httptest.NewTestServer(t, h)`, an in-memory
  server that works inside the bubble and closes itself.
- Any package that starts goroutines verifies none leak:
  `goleak.VerifyTestMain(m)` in `TestMain`, or `defer goleak.VerifyNone(t)`.
  `-race` finds data races; it does not find a goroutine that never exits.

## 8. Test Context, Benchmarks, and Artifacts

- `t.Context()` (Go 1.24+) instead of `context.Background()` — it is
  cancelled before `t.Cleanup` runs, so blocked work unwinds when the test
  ends.
- Benchmarks use `for b.Loop()` (Go 1.24+): setup runs once, results stay
  alive without a sink. Add `b.ReportAllocs()` and compare runs with
  `benchstat`.
- `t.Attr` (Go 1.25+) emits key/value pairs CI can parse;
  `t.ArtifactDir()` with `go test -artifacts` (Go 1.26+) keeps failing
  golden output or captured bodies outside the repository.

Examples for both sections: `references/concurrency-and-benchmarks.md`.

## 9. Assertion Library Traps

- **Build `assert.New(t)` / `require.New(t)` inside each `t.Run`.** An
  instance created from the parent `t` reports a subtest's failure against
  the parent, and the failing subtest itself prints `PASS`.
- **`require`, `t.Fatal` and `t.FailNow` only on the test goroutine.**
  From a spawned goroutine they cannot stop the test. Send results back on
  a channel and assert after receiving. `go vet`'s `testinggoroutine` and
  golangci-lint's `testifylint` catch most cases.
- **`require` for preconditions, `assert` for independent checks** — a
  failed precondition should stop the test before it nil-panics.
- **`assert.Eventually` hides timing bugs** in polling; prefer `synctest`.

## Anti-Patterns

- 🔴 Test with no assertions — always passes, proves nothing
- 🔴 `time.Sleep` for synchronization — use `testing/synctest`, channels, or polling
- 🔴 Test depends on execution order — each test must stand alone
- 🔴 Mocking everything — you end up testing your mocks, not your code
- 🟡 Test names like `Test1`, `TestSuccess` — name the scenario
- 🟡 Reaching into private fields — test through the public API
- 🟡 No edge cases: empty, nil, zero, max values, unicode
- 🟡 Giant shared setup — each test should set up only what it needs
- 🟡 `context.Background()` in a test — use `t.Context()`
- 🟡 `for range b.N` on Go 1.24+ — use `for b.Loop()`
- 🟢 Fuzz anything that takes untrusted input
- 🟢 Golden files for complex output comparisons

## Verification Checklist

1. Every test has meaningful assertions (no empty test bodies)
2. Test names describe the scenario, not the method
3. `t.Helper()` called in every test utility function
4. `t.Cleanup()` used for resource teardown
5. `t.Parallel()` used where safe, avoided where not
6. Integration tests guarded with `testing.Short()` or build tags
7. Mocks are minimal — only mock external dependencies
8. No `time.Sleep` for synchronization anywhere in the suite
9. Packages that start goroutines verify with `goleak`
10. Benchmarks use `for b.Loop()` and call `b.ReportAllocs()`
11. Edge cases covered: empty, nil, zero, boundary values
12. `go test -race ./...` passes
13. Coverage is used to find gaps; CI enforces a ratcheting floor, not a target
14. testify instances are built per subtest; no `require` off the test goroutine

© eduardo-sl · MIT · eduardo-sl/go-agent-skills

Похожие скиллы

Все скиллы по теме «Тесты и QA» →
improve-codebase-architecture Matt Pocock Скилл ищет архитектурные узкие места в кодовой базе и показывает варианты углубления модулей в HTML-отчёте. Подойдёт для ревью перед рефакторингом. 1 163 035установок design-taste-frontend Leonxlnx Скилл задаёт арт-дирекцию для публичных страниц и рабочих экранов, а затем проверяет результат в браузере по скриншотам. Нужен, когда интерфейс выглядит шаблонным или недоработанным. CX Codex +1 678 700установок tdd Matt Pocock Скилл управляет циклом красный-зелёный в TDD: проверяет, что тесты пишутся до кода, держит их на уровне публичных интерфейсов и не завязывает на внутреннюю структуру. 1 141 062установок skill-creator официальный anthropics Помогает создать новый скилл, доработать существующий и проверить результат через тестовые промпты и оценки. 414 180установок agent-browser vercel-labs Скилл управляет браузером через CLI: открывает страницы, заполняет формы, нажимает кнопки и проверяет веб-приложения. Подходит для задач, где агенту нужно действовать в интерфейсе. CX Codex +1 1 200 000установок prototype Matt Pocock Создаёт временный прототип, чтобы проверить логику, модель состояния или вид интерфейса до работы над основным кодом. 986 201установок

Из того же набора22

go-semantic-tools Ищет вызовы, реализации и зависимости в Go-проектах через gopls и go list, а не текстовый поиск. Понимает интерфейсы, embedding и cross-package использование — то, что grep не видит. CX Codex +1 ★ 83звёзд репо go-dependency-audit Скилл проверяет зависимости Go-модуля на уязвимости, устаревшие версии и проблемы в go.mod. Пригодится перед обновлением или ревью зависимостей. CX Codex +1 ★ 83звёзд репо go-ci Скилл помогает агенту писать и настраивать GitHub Actions для Go-проектов. Нужен, когда нужна пайплайн с линтингом, тестами, проверками безопасности и кешированием. CX Codex +1 ★ 83звёзд репо git-commit Скилл учит агента писать коммиты по Conventional Commits: тип, область, императив в заголовке. Пригодится, когда история коммитов в проекте превратилась в кашу. CX Codex +1 ★ 83звёзд репо go-troubleshooting Скилл ведёт агента по диагностике рантайм-проблем в Go: паники, дедлоки, утечки горутин и памяти, отчёты race detector. Пригодится, когда программа падает или висит, а причина неясна. CX Codex +1 ★ 83звёзд репо go-performance-review Скилл ищет узкие места в Go-коде и помогает проверять оптимизации бенчмарками и профилями. Пригодится для ревью горячих путей и снижения аллокаций. CX Codex +1 ★ 83звёзд репо go-observability Скилл для Go-сервисов: помогает настроить структурные логи на log/slog, трейсы и метрики через OpenTelemetry, а также алерты по SLO. Пригодится, когда сервис уже в проде и нужно видеть, что в нём происходит. CX Codex +1 ★ 83звёзд репо go-concurrency-review Скилл проверяет конкурентный код на Go: жизненный цикл горутин, каналы, общие данные и передачу контекста. Пригодится для ревью, поиска гонок и проектирования конвейеров. CX Codex +1 ★ 83звёзд репо

Спонсоры проекта

Компании, которые помогают держать аналитику открытой