mcpField
T
testing

testing

github.com/scientiacapital测试与质量2875 次安装4 周前更新
代码仓库

关于 testing

面向软件开发者的通用测试技能,提供 TDD、测试分层、模拟和覆盖率指导。内容适用于 pytest、vitest、jest 等框架,强调验证行为并保持测试可靠、易维护。

主要功能

  1. 01TDD 红绿重构流程
  2. 02单元、集成与端到端测试分层
  3. 03外部依赖模拟策略
  4. 04测试组织与命名建议
  5. 05覆盖率目标和完成检查清单
  6. 06pytest、vitest 与 jest 示例

适用场景

  1. 01为新功能先编写失败测试,再逐步实现
  2. 02规划单元、集成和端到端测试的比例
  3. 03为 API、数据库等外部依赖设计模拟
  4. 04检查测试覆盖率、独立性与稳定性

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/scientiacapital/skills --skill testing

安装后在 Claude Code 中输入/testing确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

config.json
reference/
coverage-strategies.md
integration-testing.md
test-organization.md
unit-testing.md

详细介绍

涵盖 TDD 工作流、测试金字塔策略、模拟模式和覆盖率指导的综合测试技能。适用于 pytest、vitest、jest 及其他测试框架的通用模式。

此技能强调编写能带来信心、又不会成为维护负担的测试。测试应快速、可靠,并聚焦于行为而非实现细节。

<quick_start> TDD 红-绿-重构循环:

  1. 红:先编写一个失败的测试

    test('adds numbers', () => {
      expect(add(1, 2)).toBe(3);  // Fails - add() doesn't exist
    });
    
  2. 绿:编写能通过测试的最少代码

    const add = (a, b) => a + b;  // Test passes
    
  3. 重构:在测试保持通过的同时清理代码

测试金字塔:70% 单元测试、25% 集成测试、5% 端到端测试 </quick_start>

<success_criteria> 满足以下条件即表示测试成功:

  • 遵循 TDD 循环:先于实现代码编写测试
  • 测试金字塔均衡:约 70% 单元测试、25% 集成测试、5% 端到端测试
  • 测试相互独立,可按任意顺序运行
  • 没有不稳定的测试(运行 3 次以验证可靠性)
  • 覆盖率达到目标:行覆盖率 70%–80%,关键路径 100%
  • 测试名称描述行为(内容 + 时机 + 预期结果)
  • 仅对外部依赖使用模拟,不模拟自己的代码 </success_criteria>

<core_principles>

测试思维

  1. 测试就是文档——失败的测试是尚未实现的规范
  2. 测试行为,而非实现——重构后测试仍应有效
  3. 快速反馈循环——单元测试应以毫秒而非秒为单位运行
  4. 默认隔离——每个测试都应相互独立
  5. 准备-执行-断言——每个测试都应有清晰的结构 </core_principles>

<tdd_workflow>

TDD:红-绿-重构

┌─────────────────────────────────────────────────────────┐
│                    TDD CYCLE                             │
│                                                          │
│    ┌─────────┐                                          │
│    │   RED   │ ◄─── Write a failing test                │
│    └────┬────┘                                          │
│         │                                                │
│         ▼                                                │
│    ┌─────────┐                                          │
│    │  GREEN  │ ◄─── Write minimum code to pass          │
│    └────┬────┘                                          │
│         │                                                │
│         ▼                                                │
│    ┌─────────┐                                          │
│    │REFACTOR │ ◄─── Clean up while tests stay green     │
│    └────┬────┘                                          │
│         │                                                │
│         └──────────────► Back to RED                    │
└─────────────────────────────────────────────────────────┘
规则
  1. 先编写一个失败的测试——没有失败的测试,绝不编写生产代码
  2. 只编写足以让测试失败的内容——编译失败也算失败
  3. 只编写足以通过测试的代码——不多不少
  4. 只在测试通过时重构——测试失败时绝不重构
常见的 TDD 错误
错误错误原因应采取的做法
编写代码后再写测试测试会沦为确认偏误红-绿-重构
测试私有方法测试的是实现,而非行为测试公开接口
测试复杂度跨度过大难以调试失败原因循序渐进
跳过重构步骤技术债务会不断累积始终清理代码
</tdd_workflow>

<test_pyramid>

测试金字塔

                    ┌───────────┐
                    │    E2E    │  Few, slow, expensive
                    │   Tests   │  (minutes)
                    └─────┬─────┘
                          │
               ┌──────────┴──────────┐
               │   Integration Tests  │  Some, medium speed
               │   (API, Database)    │  (seconds)
               └──────────┬───────────┘
                          │
        ┌─────────────────┴─────────────────┐
        │          Unit Tests                │  Many, fast, cheap
        │    (Functions, Components)         │  (milliseconds)
        └────────────────────────────────────┘
分布指南
类型百分比速度范围
单元测试70%–80%每个 <10ms单个函数/组件
集成测试15%–25%每个 <1s多个组件、数据库
端到端测试5%–10%每个 <30s完整用户流程
各类测试的测试内容

单元测试:

  • 纯函数
  • 业务逻辑
  • 数据转换
  • 验证规则
  • 组件渲染

集成测试:

  • API 端点
  • 数据库操作
  • 服务交互
  • 组件集成

端到端测试:

  • 关键用户流程(登录、结账)
  • 仅测试正常流程
  • 冒烟测试 </test_pyramid>

<when_to_mock>

模拟策略

伦敦学派与底特律学派

伦敦学派(模拟派):

  • 模拟所有依赖
  • 在完全隔离的环境中测试
  • 测试非常聚焦

底特律学派(经典派):

  • 只模拟外部服务
  • 将自然形成的单元放在一起测试
  • 测试更贴近实际

推荐:采用务实方法

  • 模拟外部服务(API、单元测试中的数据库)
  • 除非必要,否则不要模拟自己的代码
  • 在集成测试中使用真实实现
应该模拟的内容
模拟不模拟
外部 API自己的纯函数
文件系统(单元测试中)数据转换
网络请求业务逻辑
时间/随机性内存数据结构
昂贵的计算简单工具函数
模拟模式
// GOOD: Mock external dependency
const mockFetch = vi.fn().mockResolvedValue({ data: [] });

// BAD: Mocking your own utilities
const mockFormatDate = vi.fn(); // Don't do this

// GOOD: Dependency injection for testability
function createService(httpClient = fetch) {
  return {
    getData: () => httpClient('/api/data')
  };
}

// In test:
const mockClient = vi.fn();
const service = createService(mockClient);

</when_to_mock>

<test_structure>

测试组织

文件命名
src/
├── components/
│   ├── Button.tsx
│   └── Button.test.tsx      # Colocated test
├── utils/
│   ├── format.ts
│   └── format.test.ts
└── __tests__/               # Or separate folder
    └── integration/
        └── api.test.ts
测试命名
// Pattern: describe what + when + expected result
describe('UserService', () => {
  describe('createUser', () => {
    it('returns user object when given valid email', () => {});
    it('throws ValidationError when email is invalid', () => {});
    it('sends welcome email after successful creation', () => {});
  });
});

// Alternative: BDD style
describe('UserService', () => {
  describe('when creating a user with valid data', () => {
    it('should return the created user', () => {});
    it('should send a welcome email', () => {});
  });

  describe('when email is invalid', () => {
    it('should throw ValidationError', () => {});
  });
});

</test_structure>

Arrange-Act-Assert
it('calculates total with discount', () => {
  // Arrange - set up test data
  const cart = createCart([
    { price: 100, quantity: 2 },
    { price: 50, quantity: 1 }
  ]);
  const discount = 0.1;

  // Act - perform the action
  const total = calculateTotal(cart, discount);

  // Assert - verify result
  expect(total).toBe(225); // (200 + 50) * 0.9
});

</test_structure>

<what_not_to_test>

不要测试的内容

跳过以下内容
  1. 框架代码 - React 的 useState、Express 路由
  2. 第三方库 - 它们有自己的测试
  3. 简单的 getter/setter - 没有逻辑 = 无需测试
  4. 实现细节 - 私有方法、内部状态
  5. 单行函数 - 除非包含复杂逻辑
重点关注
  1. 业务逻辑 - Bug 藏身之处
  2. 边界情况 - 空值、空数组、边界
  3. 错误路径 - 出错时会发生什么
  4. 面向用户的行为 - 用户实际执行的操作
  5. 回归问题 - 曾经修复又再次出现的 Bug
覆盖率目标
指标目标说明
行覆盖率70-80%越高并不总是越好
分支覆盖率70-80%比行覆盖率更重要
关键路径100%身份验证、支付、数据变更

警告: 100% 的覆盖率并不意味着测试质量好。糟糕的测试可以覆盖每一行代码,却没有测试任何有意义的内容。 </what_not_to_test>

如需了解详细模式,请加载相应参考资料:
主题参考文件加载时机
单元测试模式reference/unit-testing.md编写单元测试、使用模拟
集成测试reference/integration-testing.mdAPI 测试、数据库测试
测试组织reference/test-organization.md组织测试套件
覆盖率策略reference/coverage-strategies.md设定覆盖率目标

加载方式: 请求特定主题,或根据上下文判断是否需要加载。

<framework_patterns>

按框架分类的快速参考

pytest(Python)
# Fixtures
@pytest.fixture
def user():
    return User(name="test")

def test_user_greet(user):
    assert user.greet() == "Hello, test"

# Parametrize
@pytest.mark.parametrize("input,expected", [
    ("hello", "HELLO"),
    ("world", "WORLD"),
])
def test_uppercase(input, expected):
    assert uppercase(input) == expected
vitest/jest(TypeScript)
// Basic test
test('adds numbers', () => {
  expect(add(1, 2)).toBe(3);
});

// Mock
vi.mock('./api', () => ({
  fetchUser: vi.fn().mockResolvedValue({ name: 'test' })
}));

// Component test
import { render, screen } from '@testing-library/react';

test('renders button', () => {
  render(<Button>Click</Button>);
  expect(screen.getByRole('button')).toHaveTextContent('Click');
});
Testing Library 原则
  1. 按角色查询,而不是按测试 ID 查询
  2. 测试用户看到的内容,而不是实现方式
  3. 优先使用 userEvent,而不是 fireEvent
  4. 避免测试内部状态 </framework_patterns>
## 测试清单

标记代码完成前:

  • 单元测试覆盖正常路径
  • 单元测试覆盖错误情况
  • 已测试边界情况(空值、空内容、边界)
  • API 端点有集成测试
  • 没有不稳定的测试(运行 3 次进行验证)
  • 测试彼此独立(可按任意顺序运行)
  • 测试名称描述行为
  • 没有硬编码的超时时间(使用 waitFor)
  • 每次测试之间都会重置模拟对象
  • 覆盖率符合项目标准

输出结果旁路文件

最后一步,将内容写入 ~/.claude/skill-analytics/last-outcome-testing.json:

{"ts":"[UTC ISO8601]","skill":"testing","version":"1.0.0","variant":"default",
 "status":"[success|partial|error]","runtime_ms":[estimated ms from start],
 "metrics":{"tests_written":[n],"coverage_delta_pct":[n]},
 "error":null,"session_id":"[YYYY-MM-DD]"}

如果部分阶段失败但已生成结果,请使用状态 "partial"。仅当未生成任何输出时,才使用 "error"。

评论

支持 Markdown