Token导航 LogoToken导航TokenDH.com
前端设计只读github未标认证来源可访问clear审计通过

testify-tdd作证 tdd

Agent Skill

用于辅助测试设计、自动化测试、用例整理和回归验证。它适合让 Agent 编写单元测试、端到端测试、测试计划或根据失败日志定位问题。使用时需要确认项目测试框架、运行命令和夹具数据,避免为了通过测试而改坏真实逻辑;涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。

总安装

533

周安装

22

GitHub Stars

4

下载量

174
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:testify-tdd(作证 tdd)
来源仓库:https://github.com/linehaul-ai/linehaulai-claude-marketplace
仓库路径:skills/testify-tdd
安装命令:
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill testify-tdd
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/linehaul-ai/linehaulai-claude-marketplace --skill testify-tdd

简介

用于辅助测试设计、自动化测试、用例整理和回归验证。

  • 适合让 Agent 编写单元测试、端到端测试或根据失败日志定位问题。
  • 使用时需确认项目测试框架、运行命令和夹具数据,避免修改真实逻辑。
  • 涉及浏览器或外部服务时,应区分本地模拟、测试环境和生产环境。
  • 安装方式:通过 npx skills add 命令从 GitHub 仓库安装。

SKILL.md

Go Testing with Testify and TDD

Comprehensive guide for writing Go tests using stretchr/testify and following Test-Driven Development methodology.

Installation

go get github.com/stretchr/testify

Testify Packages Overview

PackagePurposeWhen to Use
testify/assertAssertions that continue on failureMultiple independent checks in one test
testify/requireAssertions that halt on failurePrerequisites that must pass to continue
testify/mockInterface mockingIsolating dependencies in unit tests
testify/suiteTest organizationRelated tests sharing setup/teardown

Assert vs Require

Critical distinction: Choose based on whether the test should continue after failure.

Use require for Prerequisites

func TestUserService_GetByID(t *testing.T) {
    // Prerequisites - if these fail, nothing else matters
    db, err := setupTestDB()
    require.NoError(t, err, "database setup must succeed")
    require.NotNil(t, db, "database connection required")

    user, err := service.GetByID(ctx, userID)
    require.NoError(t, err)  // Can't verify user if this fails

    // Verifications - these can use assert
    assert.Equal(t, expectedName, user.Name)
    assert.Equal(t, expectedEmail, user.Email)
    assert.True(t, user.IsActive)
}

Use assert for Multiple Independent Checks

func TestOrderValidation(t *testing.T) {
    order := createTestOrder()
    errors := order.Validate()

    // All checks run even if earlier ones fail
    assert.NotEmpty(t, order.ID, "order should have ID")
    assert.Greater(t, order.Total, 0.0, "total should be positive")
    assert.NotEmpty(t, order.Items, "order should have items")
    assert.Empty(t, errors, "validation should pass")
}

Common Assertion Methods

// Equality
assert.Equal(t, expected, actual)
assert.NotEqual(t, expected, actual)
assert.EqualValues(t, expected, actual)  // Type-coerced comparison

// Nil checks
assert.Nil(t, value)
assert.NotNil(t, value)

// Boolean
assert.True(t, condition)
assert.False(t, condition)

// Collections
assert.Empty(t, collection)
assert.NotEmpty(t, collection)
assert.Len(t, collection, expectedLen)
assert.Contains(t, collection, element)
assert.ElementsMatch(t, expected, actual)  // Order-independent

// Errors
assert.NoError(t, err)
assert.Error(t, err)
assert.ErrorIs(t, err, expectedErr)
assert.ErrorContains(t, err, "substring")

// Comparisons
assert.Greater(t, a, b)
assert.GreaterOrEqual(t, a, b)
assert.Less(t, a, b)
assert.LessOrEqual(t, a, b)

// Strings
assert.Contains(t, str, substring)
assert.Regexp(t, pattern, str)

// JSON
assert.JSONEq(t, expectedJSON, actualJSON)

// Time
assert.WithinDuration(t, expected, actual, delta)

Table-Driven Tests

The idiomatic Go pattern for testing multiple scenarios.

func TestCalculateDiscount(t *testing.T) {
    tests := []struct {
        name           string
        orderTotal     float64
        customerTier   string
        expectedDiscount float64
        expectError    bool
    }{
        {
            name:           "no discount for small orders",
            orderTotal:     50.00,
            customerTier:   "standard",
            expectedDiscount: 0,
        },
        {
            name:           "10% discount for gold tier",
            orderTotal:     100.00,
            customerTier:   "gold",
            expectedDiscount: 10.00,
        },
        {
            name:           "20% discount for platinum over $500",
            orderTotal:     600.00,
            customerTier:   "platinum",
            expectedDiscount: 120.00,
        },
        {
            name:        "error for negative total",
            orderTotal:  -10.00,
            expectError: true,
        },
    }

    for _, tc := range tests {
        t.Run(tc.name, func(t *testing.T) {
            discount, err := CalculateDiscount(tc.orderTotal, tc.customerTier)

            if tc.expectError {
                require.Error(t, err)
                return
            }

            require.NoError(t, err)
            assert.Equal(t, tc.expectedDiscount, discount)
        })
    }
}

Interface Mocking

Define the Mock

import "github.com/stretchr/testify/mock"

// UserRepository is the interface to mock
type UserRepository interface {
    GetByID(ctx context.Context, id string) (*User, error)
    Save(ctx context.Context, user *User) error
    Delete(ctx context.Context, id string) error
}

// MockUserRepository implements UserRepository for testing
type MockUserRepository struct {
    mock.Mock
}

func (m *MockUserRepository) GetByID(ctx context.Context, id string) (*User, error) {
    args := m.Called(ctx, id)
    if args.Get(0) == nil {
        return nil, args.Error(1)
    }
    return args.Get(0).(*User), args.Error(1)
}

func (m *MockUserRepository) Save(ctx context.Context, user *User) error {
    args := m.Called(ctx, user)
    return args.Error(0)
}

func (m *MockUserRepository) Delete(ctx context.Context, id string) error {
    args := m.Called(ctx, id)
    return args.Error(0)
}

Use the Mock in Tests

func TestUserService_UpdateEmail(t *testing.T) {
    ctx := context.Background()
    userID := "user-123"
    newEmail := "new@example.com"

    existingUser := &User{
        ID:    userID,
        Email: "old@example.com",
        Name:  "Test User",
    }

    // Create mock
    mockRepo := new(MockUserRepository)

    // Set expectations
    mockRepo.On("GetByID", ctx, userID).Return(existingUser, nil)
    mockRepo.On("Save", ctx, mock.MatchedBy(func(u *User) bool {
        return u.ID == userID && u.Email == newEmail
    })).Return(nil)

    // Create service with mock
    service := NewUserService(mockRepo)

    // Execute
    err := service.UpdateEmail(ctx, userID, newEmail)

    // Verify
    require.NoError(t, err)
    mockRepo.AssertExpectations(t)
}

Mock Argument Matchers

// Exact match
mockRepo.On("GetByID", ctx, "user-123")

// Any value of type
mockRepo.On("GetByID", mock.Anything, mock.AnythingOfType("string"))

// Custom matcher
mockRepo.On("Save", ctx, mock.MatchedBy(func(u *User) bool {
    return u.Email != "" && u.ID != ""
}))

// Verify call count
mockRepo.AssertNumberOfCalls(t, "GetByID", 2)
mockRepo.AssertCalled(t, "Save", ctx, mock.Anything)
mockRepo.AssertNotCalled(t, "Delete", mock.Anything, mock.Anything)

Mock Return Values

// Return specific values
mockRepo.On("GetByID", ctx, "exists").Return(&User{ID: "exists"}, nil)
mockRepo.On("GetByID", ctx, "not-found").Return(nil, ErrNotFound)

// Return dynamically
mockRepo.On("Save", ctx, mock.Anything).Return(nil).Run(func(args mock.Arguments) {
    user := args.Get(1).(*User)
    user.ID = "generated-id"  // Modify the argument
})

// Return different values on successive calls
mockRepo.On("GetByID", ctx, "user-1").Return(&User{}, nil).Once()
mockRepo.On("GetByID", ctx, "user-1").Return(nil, ErrNotFound).Once()

Test Suites

Organize related tests with shared setup and teardown.

import (
    "testing"
    "github.com/stretchr/testify/suite"
)

type UserServiceTestSuite struct {
    suite.Suite
    service  *UserService
    mockRepo *MockUserRepository
    ctx      context.Context
}

// SetupSuite runs once before all tests
func (s *UserServiceTestSuite) SetupSuite() {
    s.ctx = context.Background()
}

// SetupTest runs before each test
func (s *UserServiceTestSuite) SetupTest() {
    s.mockRepo = new(MockUserRepository)
    s.service = NewUserService(s.mockRepo)
}

// TearDownTest runs after each test
func (s *UserServiceTestSuite) TearDownTest() {
    s.mockRepo.AssertExpectations(s.T())
}

// Test methods must start with "Test"
func (s *UserServiceTestSuite) TestGetByID_Success() {
    expected := &User{ID: "123", Name: "Test"}
    s.mockRepo.On("GetByID", s.ctx, "123").Return(expected, nil)

    user, err := s.service.GetByID(s.ctx, "123")

    s.Require().NoError(err)
    s.Equal(expected.Name, user.Name)
}

func (s *UserServiceTestSuite) TestGetByID_NotFound() {
    s.mockRepo.On("GetByID", s.ctx, "999").Return(nil, ErrNotFound)

    user, err := s.service.GetByID(s.ctx, "999")

    s.Nil(user)
    s.ErrorIs(err, ErrNotFound)
}

// Run the suite
func TestUserServiceSuite(t *testing.T) {
    suite.Run(t, new(UserServiceTestSuite))
}

TDD Workflow: Red-Green-Refactor

1. Red: Write a Failing Test First

func TestShippingCalculator_CalculateCost(t *testing.T) {
    calc := NewShippingCalculator()

    cost, err := calc.CalculateCost(Weight(5.0), Zone("US-WEST"))

    require.NoError(t, err)
    assert.Equal(t, Money(12.50), cost)
}

Run the test - it should fail (function doesn't exist or returns wrong value).

2. Green: Write Minimal Code to Pass

func (c *ShippingCalculator) CalculateCost(weight Weight, zone Zone) (Money, error) {
    // Minimal implementation to make the test pass
    return Money(12.50), nil
}

Run the test - it should pass.

3. Refactor: Improve While Keeping Tests Green

func (c *ShippingCalculator) CalculateCost(weight Weight, zone Zone) (Money, error) {
    baseRate := c.getBaseRate(zone)
    weightCharge := weight.Kilograms() * c.ratePerKg
    return Money(baseRate + weightCharge), nil
}

Run tests after each refactor to ensure they still pass.

4. Add More Test Cases

func TestShippingCalculator_CalculateCost(t *testing.T) {
    tests := []struct {
        name         string
        weight       Weight
        zone         Zone
        expectedCost Money
        expectError  bool
    }{
        {"small package US-WEST", Weight(1.0), Zone("US-WEST"), Money(5.00), false},
        {"medium package US-WEST", Weight(5.0), Zone("US-WEST"), Money(12.50), false},
        {"large package US-EAST", Weight(10.0), Zone("US-EAST"), Money(22.00), false},
        {"zero weight error", Weight(0), Zone("US-WEST"), Money(0), true},
        {"negative weight error", Weight(-1), Zone("US-WEST"), Money(0), true},
    }

    calc := NewShippingCalculator()

    for _, tc := range tests {
        t.Run(tc.name, func(t *testing.T) {
            cost, err := calc.CalculateCost(tc.weight, tc.zone)

            if tc.expectError {
                require.Error(t, err)
                return
            }

            require.NoError(t, err)
            assert.Equal(t, tc.expectedCost, cost)
        })
    }
}

Test File Organization

Same-Package Tests (Unit Tests)

// user_service.go
package users

type UserService struct { ... }

// user_service_test.go
package users  // Same package - can test private functions

func TestUserService_validateEmail(t *testing.T) {
    // Can access private method validateEmail
}

Black-Box Tests (Integration Tests)

// user_repository_integration_test.go
package users_test  // Different package - tests public API only

import "myapp/internal/users"

func TestUserRepository_Create(t *testing.T) {
    // Can only access public API
    repo := users.NewRepository(db)
}

Test Naming Conventions

Test[Unit]_[Scenario]_[ExpectedBehavior]

Examples:
- TestUserService_GetByID_ReturnsUser
- TestUserService_GetByID_ReturnsErrorWhenNotFound
- TestCalculateDiscount_GoldTier_Returns10Percent
- TestOrderValidator_EmptyItems_ReturnsValidationError

Running Tests

# Run all tests
go test ./...

# Verbose output
go test -v ./...

# Disable test caching
go test -count=1 ./...

# Run specific test
go test -v -run TestUserService ./...

# Run with coverage
go test -cover ./...

# Generate coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Best Practices

  1. One logical assertion per test - Test one behavior, though you may have multiple assert calls
  2. Descriptive test names - The name should explain what's being tested
  3. Arrange-Act-Assert pattern - Structure tests clearly
  4. Use require for setup, assert for verification
  5. Table-driven tests for multiple scenarios - Avoid copy-paste test code
  6. Mock at interface boundaries - Don't mock what you don't own
  7. Keep tests independent - No shared state between tests
  8. Test edge cases - Empty inputs, nil, zero values, boundaries
  9. Don't test implementation details - Test behavior, not internal structure
  10. Verify mock expectations - Always call AssertExpectations(t)

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

29.27%
按下载量换算51

Gemini CLI

22.73%
按下载量换算40

Antigravity

17.87%
按下载量换算31

windsurf

12.41%
按下载量换算22

Codex

8.63%
按下载量换算15

OpenCode

3.8%
按下载量换算7

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

只读

该 Skill 主要提供规则、说明或参考内容,本身偏只读;真正读写文件、联网或执行命令仍取决于宿主 Agent 的任务。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills