测试助手
- 作者仓库星标 0
- 作者更新于 实时读取
- 作者仓库 skills-registry
- 领域
- AI 智能
- 兼容 Agent
-
- Claude Code
- Cursor
- Cline
- Codex
- Windsurf
- Gemini CLI
- +20
- 信任分
- 88 / 100 · 社区维护
- 作者 / 版本 / 许可
- @tomevault-io · 未声明 license
- Token 消耗评级
- 低消耗
- 接入复杂程度
- 需简单配置
- 是否需要外部 API Key
- 不需要
- 兼容的系统
- 未声明(默认跨平台)
- 底层运行要求
- 无特殊要求
- 文件与系统权限
-
- 只读
- 允许写入 / 修改
- Shell 执行
- 读取环境变量
- 网络行为
- 仅限本地
- 安装命令数
- 26 条
档案由构建时根据 SKILL.md 与安装命令自动衍生,可能与作者实际意图存在差异。
需要注意: 未限定 allowed-tools,默认拥有全部工具权限。
---
name: golang-testing
description: Write idiomatic Go tests. Use when this capability is needed. Use this skill when writing, revie…
category: AI 智能
runtime: 无特殊运行时
---
# golang-testing 输出预览
## PART A: 任务判断
- 适用问题:提示词、Agent 工作流、模型评估或自动化推理。
- 输入要求:目标材料、限制条件、期望输出和验收方式。
- 证据边界:围绕“When to Use / Default Testing Stance / Core Principles”读取原文规则,不把推断写成作者承诺。
## PART B: 执行结果
- **01** 任务判断:确认你的需求是否属于提示词、Agent 工作流、模型评估或自动化推理,并标出输入、限制和预期结果。
- **02** 执行计划:优先按“When to Use / Default Testing Stance / Core Principles”拆成步骤,说明每一步会读取什么、修改什么、产出什么。
- **03** 交付结果:给出可复制的命令、文件改动、检查清单或内容草稿,并说明如何继续迭代。
- **04** 风险边界:结合 读取文件、写入/修改文件、执行终端命令、读取环境变量、主要在本地完成、通常不需要额外 API Key 给出执行前确认项。
## Running Rules
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;主要在本地完成;通常不需要额外 API Key。
- 先小样例验证,再放大到真实任务。
- 交付时同时给结果、检查口径和下一步迭代建议。 原文没有稳定的斜杠命令要求。安装验证后通常全局生效,直接在对话里点名这个 Skill 并描述任务即可。
告诉 Agent 目标文件或材料、期望结果、不可改范围、是否允许联网或执行命令。本 Skill 的权限画像是:读取文件、写入/修改文件、执行终端命令、读取环境变量。
先用一个小任务确认它会围绕“When to Use / Default Testing Stance / Core Principles”工作;涉及文件或命令时,先看 diff、日志、预览或测试结果。
检查最终产物是否包含明确结果、必要证据和下一步动作;如果输出泛泛而谈,就补充输入、边界和验收标准后重跑。
---
name: golang-testing
description: Write idiomatic Go tests. Use when this capability is needed. Use this skill when writing, revie…
category: AI 智能
source: tomevault-io/skills-registry
---
# golang-testing
## 什么时候使用
- 用于审阅代码、文档或方案并给出可执行反馈 适合处理AI Agent、提示词、模型评估与自动化推理,核心价值是把输入、判断、执行、验证和交付边界固定下来,避免 Agent 泛泛回答。 把任务拆成可执行、可检查、可继续迭代的步骤;通常不需要…
- 面向提示词、Agent 工作流、模型评估或自动化推理,优先处理能明确输入、步骤和验收标准的工作。
## 需要提供什么
- 目标材料、目录范围、期望结果和不可改动内容。
- 是否允许联网、执行命令、读写文件或调用外部服务。
## 执行规则
- 围绕「When to Use / Default Testing Stance / Core Principles」组织步骤,不把推断写成作者事实。
- 读取文件、写入/修改文件、执行终端命令、读取环境变量;主要在本地完成;通常不需要额外 API Key。
- 先跑小样例,确认结果可检查后再扩大任务范围。
## 输出要求
- 给出最终产物、关键证据、验证方式和下一步动作。
- 信息不足时标记 unknown,不编造命令、平台或依赖。 作者原文负责流程事实;仓库文件负责来源和命令;流狐只补充适用场景、限制和质量判断。
skill "golang-testing" {
输入层 -> 用户目标 + 目标文件 + 禁止范围 + 验收标准
上下文层 -> When to Use / Default Testing Stance / Core Principles
规则层 -> SKILL.md 触发条件 / 执行顺序 / 输出格式
运行层 -> 无特殊运行时 | 读取文件、写入/修改文件、执行终端命令、读取环境变量 | 主要在本地完成
安全层 -> 通常不需要额外 API Key + 小任务验证 + diff / 日志复核
输出层 -> 可复制结果 + 检查清单 + 下一步迭代
} Golang Testing
Use this skill when writing, reviewing, or refactoring Go tests.
When to Use
- Writing new unit, integration, or package-level tests for Go code
- Refactoring tests toward idiomatic Go structure and stronger signal
- Reviewing Go test suites for maintainability, determinism, and coverage gaps
- Designing fakes, mocks, or test seams around external dependencies
Default Testing Stance
Unless there is a clear reason not to, prefer these defaults:
- Use black-box tests with an external test package:
package mypkg_test - Test public behaviour and interfaces, not internal implementation details
- Use one top-level test function per public function/method/behaviour, with subtests for scenarios
- Call
t.Parallel()by default in top-level tests and subtests unless shared state, process-wide mutation, timing, or external resources make it unsafe - Use
t.Runsubtests by default, even when not using table-driven tests - Use table-driven tests only when there is a finite, related set of input/output scenarios that benefits from shared structure
- Use
testify/requirefor preconditions and fatal assertions, andtestify/assertfor non-fatal assertions - Use
testify/mockonly for true external-system boundaries or very small/simple seams; otherwise prefer fakes or in-memory implementations - Keep tests deterministic, hermetic, and readable
Core Principles
- Behaviour over implementation - Assert externally visible outcomes
- Fast feedback - Keep most tests cheap enough to run constantly
- Deterministic - Avoid sleeps, real clocks, network access, and ambient environment dependence
- Minimal setup - Prefer small helpers over deep fixture stacks
- High signal - Each failing test should point to one clear behaviour regression
- Coverage with intent - Cover important branches, edge cases, and error paths, not just lines
Package and File Conventions
Black-Box Test Packages
Prefer:
package user_test
import (
"testing"
"github.com/stretchr/testify/require"
"example.com/project/user"
)
Avoid:
package user
Use same-package tests only when you intentionally need access to unexported helpers and there is no better public seam. Default to _test packages.
File Organisation
- Group tests by public API surface or behaviour
- Keep helper functions near the tests that use them unless broadly reused
- Prefer
_test.gofiles named after the subject under test, such asservice_test.go,handler_test.go,client_test.go - Avoid giant catch-all files once a package grows
Preferred Test Structure
One Top-Level Test per Behaviour, Subtests per Scenario
For a public function, prefer one top-level test and scenario subtests instead of many separate TestXxx_Yyy functions.
Use t.Run even without a table when the scenarios are clearer as explicitly written examples.
func TestCreateUser(t *testing.T) {
t.Parallel()
t.Run("success", func(t *testing.T) {
t.Parallel()
got, err := user.Create("alice@example.com")
require.NoError(t, err)
assert.Equal(t, "alice@example.com", got.Email)
})
t.Run("rejects invalid email", func(t *testing.T) {
t.Parallel()
_, err := user.Create("not-an-email")
require.Error(t, err)
require.ErrorIs(t, err, user.ErrInvalidEmail)
})
}
func TestParseUserID(t *testing.T) {
t.Parallel()
tests := []struct {
name string
input string
want int
wantErr string
}{
{name: "valid", input: "42", want: 42},
{name: "empty", input: "", wantErr: "empty user id"},
{name: "invalid", input: "abc", wantErr: "invalid user id"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := user.ParseUserID(tt.input)
if tt.wantErr != "" {
require.Error(t, err)
assert.Contains(t, err.Error(), tt.wantErr)
return
}
require.NoError(t, err)
assert.Equal(t, tt.want, got)
})
}
}
Why This Pattern
- Keeps all scenarios for one behaviour together
- Makes it easy to add edge cases without duplicating setup
- Produces better output in
go test -runand CI logs - Works naturally with table-driven tests and
t.Parallel()
Parallel Test Execution
Default Rule
Call t.Parallel() unless there is a concrete reason not to.
Good candidates:
- Pure functions
- Tests using isolated in-memory state
- Tests using
t.TempDir() - Tests with per-test
httptest.Server - Table-driven subtests with isolated fixtures
Avoid or carefully isolate parallelism when tests:
- Mutate global variables, singleton state, env vars, or process working directory
- Depend on wall-clock timing or
time.Sleep - Reuse shared mocks/fakes with non-thread-safe state
- Use fixed ports, shared files, or shared databases without isolation
Parallel Subtest Safety
In Go 1.22+ modules, loop variables declared in the for statement are created per iteration, so rebinding like tt := tt is usually not needed.
Still rebind when:
- the module/package targets pre-Go-1.22 semantics
- the variable is declared outside the loop and reused
- you intentionally want compatibility with older Go module targets
For modern Go:
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// use tt safely in Go 1.22+
})
}
For older module targets:
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
// use tt safely
})
}
Testify Usage
Prefer Testify for clearer assertions.
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
require vs assert
- Use
requirewhen the test cannot continue after failure - Use
assertwhen you want multiple related checks in one scenario
func TestUserName(t *testing.T) {
t.Parallel()
u, err := user.New("alice")
require.NoError(t, err)
assert.Equal(t, "alice", u.Name())
assert.True(t, u.IsActive())
}
Prefer semantic assertions when available:
require.ErrorIsassert.Equalassert.ElementsMatchassert.Lenassert.Empty/assert.NotEmptyassert.WithinDurationassert.JSONEq
Error Testing
- Prefer asserting exported sentinel/type behaviour with
ErrorIs/ErrorAs - Avoid brittle full-string equality unless the exact message is part of the contract
- Assert both success and failure paths for public APIs
require.ErrorIs(t, err, user.ErrNotFound)
Good Coverage Practices
Aim for coverage that reflects risk and behaviour, not vanity percentages.
Always Cover
- Happy path
- Input validation failures
- Boundary values
- Zero values and empty collections
- Domain-specific edge cases
- External dependency failures
- Serialization/parsing failures
- Context cancellation / timeout paths when relevant
- Idempotency or retry semantics when relevant
Coverage Heuristics
- Add a test for every bug fix before or with the fix
- Cover each exported public method/function with at least one success and one failure/edge scenario where meaningful
- Prefer focused unit tests for combinatorial logic and a smaller number of integration tests for end-to-end confidence
- If a branch matters to production behaviour, it deserves an assertion
- Remove duplicate tests that do not add behavioural signal
Coverage Commands
go test ./...
go test ./... -cover
go test ./... -coverprofile=coverage.out
go tool cover -func=coverage.out
go tool cover -html=coverage.out
Integration vs Unit Tests
Use the lightest test that proves the behaviour.
Prefer Unit Tests For
- Pure transformations and validation
- Orchestration logic with fake dependencies
- Error mapping and branching logic
Prefer Integration Tests For
- SQL queries and repository behaviour
- HTTP handlers, middleware, and routing
- Serialization boundaries
- Interactions with real adapters that are cheap and deterministic to run locally/CI
When an integration test gives stronger confidence with similar complexity, prefer it over elaborate mocking.
Mocking Guidance
Default Rule
Mock only external systems or very thin boundaries. Prefer fakes and in-memory implementations for richer domain behaviour.
Prefer:
- In-memory repositories
httptest.Server- Temporary directories
fstest.MapFS- Fixed clocks / injectable time sources
Reach for testify/mock when:
- The dependency is an external system boundary
- A fake would be more complex than the behaviour being tested
- You need precise call assertions on a thin collaborator
Avoid mocks for:
- Your own core domain models
- Simple data containers
- Behaviour that is easier to express with an in-memory fake
- Deep implementation-driven interaction testing
Testify Mock Pattern
type MockMailer struct {
mock.Mock
}
func (m *MockMailer) Send(ctx context.Context, msg mail.Message) error {
args := m.Called(ctx, msg)
return args.Error(0)
}
func TestService_SendWelcomeEmail(t *testing.T) {
t.Parallel()
mailer := new(MockMailer)
mailer.
On("Send", mock.Anything, mail.Message{To: "alice@example.com"}).
Return(nil).
Once()
svc := user.NewService(mailer)
err := svc.SendWelcomeEmail(context.Background(), "alice@example.com")
require.NoError(t, err)
mailer.AssertExpectations(t)
}
Rules:
- One mock per external dependency seam, not everywhere
- Keep expectations minimal and behaviour-focused
- Avoid over-asserting call order unless it is part of the contract
- Do not share mock instances across parallel tests
Filesystem Testing
Prefer standard-library-friendly seams and hermetic storage.
Recommended Patterns
- Inject an
fs.FSfor read-only filesystem behaviour - Use
fstest.MapFSfor small read scenarios - Use
t.TempDir()for realistic file creation/update flows - Keep filesystem access behind a small adapter if the production code is otherwise hard to isolate
fstest.MapFS Example
func TestLoadConfig(t *testing.T) {
t.Parallel()
files := fstest.MapFS{
"config.json": {Data: []byte(`{"env":"test"}`)},
}
cfg, err := config.Load(files, "config.json")
require.NoError(t, err)
assert.Equal(t, "test", cfg.Env)
}
t.TempDir() Example
func TestWriteReport(t *testing.T) {
t.Parallel()
dir := t.TempDir()
path := filepath.Join(dir, "report.txt")
err := report.Write(path, "hello")
require.NoError(t, err)
data, err := os.ReadFile(path)
require.NoError(t, err)
assert.Equal(t, "hello", string(data))
}
Avoid mocking os calls directly when a temp dir or fs.FS seam would be simpler.
HTTP Client Testing
Prefer real HTTP semantics without real network dependencies.
Recommended Patterns
- Use
httptest.Serverto test client behaviour against realistic responses - Inject
*http.Clientinto your code - For very small seams, a custom
http.RoundTripperfake can be enough - Mock higher-level gateways only when HTTP itself is not the thing under test
httptest.Server Example
func TestClient_GetUser(t *testing.T) {
t.Parallel()
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
assert.Equal(t, http.MethodGet, r.Method)
assert.Equal(t, "/users/42", r.URL.Path)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"id":42,"name":"alice"}`))
}))
t.Cleanup(srv.Close)
client := api.NewClient(srv.URL, srv.Client())
got, err := client.GetUser(context.Background(), 42)
require.NoError(t, err)
assert.Equal(t, "alice", got.Name)
}
Custom Transport Fake
For narrow client logic, prefer a tiny fake over a heavyweight mock:
type roundTripFunc func(*http.Request) (*http.Response, error)
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) {
return f(r)
}
Use this when you only need to simulate one request/response pair and httptest.Server would be unnecessary ceremony.
Time Testing
Do not depend on real time in tests.
Recommended Patterns
- Inject time via a function like
now func() time.Time - Or define a tiny clock interface at the boundary that needs it
- Use fixed timestamps in tests
- Avoid
time.Sleepas a synchronisation mechanism - Prefer contexts, channels, and explicit signals over waiting for elapsed time
Function Injection Example
type Service struct {
now func() time.Time
}
func NewService() *Service {
return &Service{now: time.Now}
}
func TestTokenExpired(t *testing.T) {
t.Parallel()
fixed := time.Date(2025, 1, 1, 12, 0, 0, 0, time.UTC)
svc := token.NewService(func() time.Time { return fixed })
assert.True(t, svc.IsExpired(fixed.Add(-time.Second)))
assert.False(t, svc.IsExpired(fixed.Add(time.Second)))
}
If production code currently calls time.Now() directly in many places, first introduce a small seam at the package boundary rather than mocking time per call site.
Table-Driven Testing Guidance
- Prefer plain
t.Runsubtests first without a table when scenarios are clearer as explicitly written examples - Use tables when the setup is mostly the same and only inputs/expectations vary
- Name cases for behaviour, not raw input values
- Keep test case structs focused; avoid giant anonymous structs with dozens of fields
- Split unrelated behaviours into separate tests instead of massive tables
Good fit for table-driven tests:
- Parsing and validation matrices
- Boundary-value checks on the same function
- Multiple related input/output combinations for deterministic logic
Poor fit for table-driven tests:
- Scenarios with materially different setup or assertions
- Behaviour tests that read more clearly as individually named
t.Runblocks - Large tables that hide intent behind many mostly-empty fields
Test Helpers
- Prefer helper functions that build valid defaults and allow explicit overrides
- Mark helpers with
t.Helper() - Return concrete values rather than hidden global state
- Keep helpers local to the package unless broad reuse justifies promotion
func newTestUser(t *testing.T, opts ...UserOption) user.User {
t.Helper()
u, err := user.New("alice", opts...)
require.NoError(t, err)
return u
}
Anti-Patterns
Avoid these unless there is a strong reason:
- Same-package white-box tests by default
- Multiple top-level tests for each small scenario of one function
- Reaching for table-driven tests when explicit
t.Runscenarios are clearer - No
t.Parallel()without reason - Real sleeps, real network calls, or dependence on current wall-clock time
- Assertion on internal private fields in black-box tests
- Brittle exact error string checks for wrapped/domain errors
- Massive shared fixtures that hide what the test actually needs
- Mock-heavy tests that mirror implementation rather than behaviour
- Coverage chasing without meaningful assertions
Review Checklist
When reviewing Go tests, check for:
- Black-box
_testpackage usage by default t.Parallel()in top-level tests and subtests unless unsafe- Subtests for multiple scenarios of one behaviour
testify/assertandtestify/requireused appropriately- Fakes preferred over mocks when practical
testify/mocklimited to external boundaries or simple seams- No hidden global state or cross-test coupling
- Deterministic handling of filesystem, HTTP, and time
- Meaningful edge-case and error-path coverage
- Tests that read like executable specifications of public behaviour
Source: brpaz/agent-skills — distributed by TomeVault.
先判断是否适合
作者设计意图
作者的方法与取舍
边界和复核