golang-stretchr-testify by samber/cc-skills-golang
npx skills add https://github.com/samber/cc-skills-golang --skill golang-stretchr-testify角色: 你是一名将测试视为可执行规范的 Go 工程师。你编写测试是为了约束行为并使失败原因不言自明——而不是为了达到覆盖率目标。
模式:
testify 通过可读的断言、模拟和测试套件来补充 Go 的 testing 包。它并不取代 testing —— 始终使用 *testing.T 作为入口点。
此技能并非详尽无遗。更多信息请参阅库文档和代码示例。Context7 可以作为一个可发现性平台提供帮助。
两者提供相同的断言。区别在于失败时的行为:
t.FailNow() —— 用于那些如果继续执行会导致 panic 或产生误导的前提条件为了提高可读性,使用 assert.New(t) / require.New(t)。将它们命名为 和 :
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
ismustfunc TestParseConfig(t *testing.T) {
is := assert.New(t)
must := require.New(t)
cfg, err := ParseConfig("testdata/valid.yaml")
must.NoError(err) // 如果解析失败则停止 —— cfg 将为 nil
must.NotNil(cfg)
is.Equal("production", cfg.Environment)
is.Equal(8080, cfg.Port)
is.True(cfg.TLS.Enabled)
}
规则 : require 用于前提条件(设置、错误检查),assert 用于验证。切勿随意混用。
is := assert.New(t)
// 相等性
is.Equal(expected, actual) // DeepEqual + 精确类型
is.NotEqual(unexpected, actual)
is.EqualValues(expected, actual) // 先转换为通用类型
is.EqualExportedValues(expected, actual)
// Nil / 布尔值 / 空值
is.Nil(obj) is.NotNil(obj)
is.True(cond) is.False(cond)
is.Empty(collection) is.NotEmpty(collection)
is.Len(collection, n)
// 包含(字符串、切片、映射键)
is.Contains("hello world", "world")
is.Contains([]int{1, 2, 3}, 2)
is.Contains(map[string]int{"a": 1}, "a")
// 比较
is.Greater(actual, threshold) is.Less(actual, ceiling)
is.Positive(val) is.Negative(val)
is.Zero(val)
// 错误
is.Error(err) is.NoError(err)
is.ErrorIs(err, ErrNotFound) // 遍历错误链
is.ErrorAs(err, &target)
is.ErrorContains(err, "not found")
// 类型
is.IsType(&User{}, obj)
is.Implements((*io.Reader)(nil), obj)
参数顺序 : 始终是 (expected, actual) —— 交换顺序会产生令人困惑的差异输出。
is.ElementsMatch([]string{"b", "a", "c"}, result) // 无序比较
is.InDelta(3.14, computedPi, 0.01) // 浮点数容差
is.JSONEq(`{"name":"alice"}`, `{"name": "alice"}`) // 忽略空白/键顺序
is.WithinDuration(expected, actual, 5*time.Second)
is.Regexp(`^user-[a-f0-9]+$`, userID)
// 异步轮询
is.Eventually(func() bool {
status, _ := client.GetJobStatus(jobID)
return status == "completed"
}, 5*time.Second, 100*time.Millisecond)
// 带有丰富断言的异步轮询
is.EventuallyWithT(func(c *assert.CollectT) {
resp, err := client.GetOrder(orderID)
assert.NoError(c, err)
assert.Equal(c, "shipped", resp.Status)
}, 10*time.Second, 500*time.Millisecond)
模拟接口以隔离被测单元。嵌入 mock.Mock,使用 m.Called() 实现方法,始终使用 AssertExpectations(t) 进行验证。
关键匹配器:mock.Anything, mock.AnythingOfType("T"), mock.MatchedBy(func)。调用修饰符:.Once(), .Times(n), .Maybe(), .Run(func)。
关于定义模拟、参数匹配器、调用修饰符、返回序列和验证,请参阅 Mock 参考。
测试套件将相关测试分组,并共享设置/拆卸逻辑。
SetupSuite() → 所有测试前执行一次
SetupTest() → 每个测试前执行
TestXxx()
TearDownTest() → 每个测试后执行
TearDownSuite() → 所有测试后执行一次
type TokenServiceSuite struct {
suite.Suite
store *MockTokenStore
service *TokenService
}
func (s *TokenServiceSuite) SetupTest() {
s.store = new(MockTokenStore)
s.service = NewTokenService(s.store)
}
func (s *TokenServiceSuite) TestGenerate_ReturnsValidToken() {
s.store.On("Save", mock.Anything, mock.Anything).Return(nil)
token, err := s.service.Generate("user-42")
s.NoError(err)
s.NotEmpty(token)
s.store.AssertExpectations(s.T())
}
// 必需的启动器
func TestTokenServiceSuite(t *testing.T) {
suite.Run(t, new(TokenServiceSuite))
}
像 s.Equal() 这样的套件方法行为类似于 assert。对于 require:s.Require().NotNil(obj)。
AssertExpectations(t) — 模拟的期望会在没有验证的情况下静默通过is.Equal(ErrNotFound, err) — 对于包装的错误会失败。使用 is.ErrorIs 来遍历错误链(expected, actual)。交换顺序会产生反向的差异输出assert — 测试在失败后继续执行,并在解引用 nil 时 panic。应使用 requiresuite.Run() — 没有启动器函数,测试会静默执行零个测试is.Equal(ptr1, ptr2) 比较的是地址。应解引用或使用 EqualExportedValues使用 testifylint 来捕获错误的参数顺序、assert/require 误用等问题。请参阅 samber/cc-skills-golang@golang-linter 技能。
samber/cc-skills-golang@golang-testing 技能samber/cc-skills-golang@golang-linter 技能每周安装量
127
代码仓库
GitHub 星标数
276
首次出现
4 天前
安全审计
安装于
opencode106
gemini-cli103
codex103
cursor103
amp102
github-copilot102
Persona: You are a Go engineer who treats tests as executable specifications. You write tests to constrain behavior and make failures self-explanatory — not to hit coverage targets.
Modes:
testify complements Go's testing package with readable assertions, mocks, and suites. It does not replace testing — always use *testing.T as the entry point.
This skill is not exhaustive. Please refer to library documentation and code examples for more informations. Context7 can help as a discoverability platform.
Both offer identical assertions. The difference is failure behavior:
t.FailNow() — use for preconditions where continuing would panic or misleadUse assert.New(t) / require.New(t) for readability. Name them is and must:
func TestParseConfig(t *testing.T) {
is := assert.New(t)
must := require.New(t)
cfg, err := ParseConfig("testdata/valid.yaml")
must.NoError(err) // stop if parsing fails — cfg would be nil
must.NotNil(cfg)
is.Equal("production", cfg.Environment)
is.Equal(8080, cfg.Port)
is.True(cfg.TLS.Enabled)
}
Rule : require for preconditions (setup, error checks), assert for verifications. Never mix randomly.
is := assert.New(t)
// Equality
is.Equal(expected, actual) // DeepEqual + exact type
is.NotEqual(unexpected, actual)
is.EqualValues(expected, actual) // converts to common type first
is.EqualExportedValues(expected, actual)
// Nil / Bool / Emptiness
is.Nil(obj) is.NotNil(obj)
is.True(cond) is.False(cond)
is.Empty(collection) is.NotEmpty(collection)
is.Len(collection, n)
// Contains (strings, slices, map keys)
is.Contains("hello world", "world")
is.Contains([]int{1, 2, 3}, 2)
is.Contains(map[string]int{"a": 1}, "a")
// Comparison
is.Greater(actual, threshold) is.Less(actual, ceiling)
is.Positive(val) is.Negative(val)
is.Zero(val)
// Errors
is.Error(err) is.NoError(err)
is.ErrorIs(err, ErrNotFound) // walks error chain
is.ErrorAs(err, &target)
is.ErrorContains(err, "not found")
// Type
is.IsType(&User{}, obj)
is.Implements((*io.Reader)(nil), obj)
Argument order : always (expected, actual) — swapping produces confusing diff output.
is.ElementsMatch([]string{"b", "a", "c"}, result) // unordered comparison
is.InDelta(3.14, computedPi, 0.01) // float tolerance
is.JSONEq(`{"name":"alice"}`, `{"name": "alice"}`) // ignores whitespace/key order
is.WithinDuration(expected, actual, 5*time.Second)
is.Regexp(`^user-[a-f0-9]+$`, userID)
// Async polling
is.Eventually(func() bool {
status, _ := client.GetJobStatus(jobID)
return status == "completed"
}, 5*time.Second, 100*time.Millisecond)
// Async polling with rich assertions
is.EventuallyWithT(func(c *assert.CollectT) {
resp, err := client.GetOrder(orderID)
assert.NoError(c, err)
assert.Equal(c, "shipped", resp.Status)
}, 10*time.Second, 500*time.Millisecond)
Mock interfaces to isolate the unit under test. Embed mock.Mock, implement methods with m.Called(), always verify with AssertExpectations(t).
Key matchers: mock.Anything, mock.AnythingOfType("T"), mock.MatchedBy(func). Call modifiers: .Once(), .Times(n), .Maybe(), .Run(func).
For defining mocks, argument matchers, call modifiers, return sequences, and verification, see Mock reference.
Suites group related tests with shared setup/teardown.
SetupSuite() → once before all tests
SetupTest() → before each test
TestXxx()
TearDownTest() → after each test
TearDownSuite() → once after all tests
type TokenServiceSuite struct {
suite.Suite
store *MockTokenStore
service *TokenService
}
func (s *TokenServiceSuite) SetupTest() {
s.store = new(MockTokenStore)
s.service = NewTokenService(s.store)
}
func (s *TokenServiceSuite) TestGenerate_ReturnsValidToken() {
s.store.On("Save", mock.Anything, mock.Anything).Return(nil)
token, err := s.service.Generate("user-42")
s.NoError(err)
s.NotEmpty(token)
s.store.AssertExpectations(s.T())
}
// Required launcher
func TestTokenServiceSuite(t *testing.T) {
suite.Run(t, new(TokenServiceSuite))
}
Suite methods like s.Equal() behave like assert. For require: s.Require().NotNil(obj).
AssertExpectations(t) — mock expectations silently pass without verificationis.Equal(ErrNotFound, err) — fails on wrapped errors. Use is.ErrorIs to walk the chain(expected, actual). Swapping produces backwards diffsassert for guards — test continues after failure and panics on nil dereference. Use requiresuite.Run() — without the launcher function, zero tests execute silentlyis.Equal(ptr1, ptr2) compares addresses. Dereference or use Use testifylint to catch wrong argument order, assert/require misuse, and more. See samber/cc-skills-golang@golang-linter skill.
samber/cc-skills-golang@golang-testing skill for general test patterns, table-driven tests, and CIsamber/cc-skills-golang@golang-linter skill for testifylint configurationWeekly Installs
127
Repository
GitHub Stars
276
First Seen
4 days ago
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode106
gemini-cli103
codex103
cursor103
amp102
github-copilot102
测试策略完整指南:单元/集成/E2E测试金字塔与自动化实践
11,200 周安装
EqualExportedValues