testing-builder
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTesting Builder
测试构建工具
Purpose
用途
Automatic test generation that learns your testing style. Eliminates the ADHD barrier to testing by making it effortless:
- Analyzes code to understand what needs testing
- Recalls your testing patterns from memory
- Generates comprehensive test suite
- Ensures all edge cases covered
- Saves testing patterns for future
For ADHD users: Zero friction - tests created instantly without manual effort.
For all users: Comprehensive coverage without the tedious work.
Learning system: Gets better at matching your testing style over time.
自动生成测试内容,适配你的测试风格。通过零操作的方式为多动症(ADHD)用户消除测试障碍:
- 分析代码以确定测试对象
- 调取记忆中的测试模式
- 生成全面的测试套件
- 确保覆盖所有边缘场景
- 保存测试模式以供后续使用
针对多动症用户:零操作成本,瞬间生成测试,无需手动投入。
针对所有用户:无需繁琐工作即可实现全面测试覆盖。
学习系统:随着使用次数增加,会更精准匹配你的测试风格。
Activation Triggers
触发条件
- User says: "write tests", "test this", "add tests", "coverage"
- After fixing bug: "create regression test"
- Code review: "needs tests"
- User mentions: "unit test", "integration test", "E2E test"
- 用户说出:"write tests"、"test this"、"add tests"、"coverage"
- 修复漏洞后:"create regression test"
- 代码评审时:"needs tests"
- 用户提及:"unit test"、"integration test"、"E2E test"
Core Workflow
核心工作流程
1. Analyze Code
1. 代码分析
Step 1: Identify what to test
javascript
// Example: Analyzing a function
function calculateDiscount(price, discountPercent, customerType) {
if (customerType === 'premium') {
discountPercent += 10;
}
return price * (1 - discountPercent / 100);
}
// Identify:
- Function name: calculateDiscount
- Parameters: price, discountPercent, customerType
- Logic branches: premium vs non-premium
- Edge cases: negative values, zero, boundary conditions
- Return type: numberStep 2: Determine test type needed
- Unit test: Pure functions, utilities, components
- Integration test: Multiple components working together, API endpoints
- E2E test: Full user workflows, critical paths
- Regression test: Specific bug that was fixed
步骤1:确定测试对象
javascript
// Example: Analyzing a function
function calculateDiscount(price, discountPercent, customerType) {
if (customerType === 'premium') {
discountPercent += 10;
}
return price * (1 - discountPercent / 100);
}
// Identify:
- Function name: calculateDiscount
- Parameters: price, discountPercent, customerType
- Logic branches: premium vs non-premium
- Edge cases: negative values, zero, boundary conditions
- Return type: number步骤2:确定所需测试类型
- Unit test:纯函数、工具类、组件
- Integration test:多组件协作、API接口
- E2E test:完整用户流程、关键路径
- Regression test:已修复的特定漏洞
2. Recall Testing Patterns
2. 调取测试模式
Query context-manager for:
search memories:
- Type: PREFERENCE, PROCEDURE
- Tags: testing, test-framework, test-style
- Project: current projectWhat to recall:
- Test framework (Jest, Vitest, Pytest, etc.)
- Assertion style (expect, assert, should)
- Test structure (describe/it, test blocks)
- Mocking patterns (jest.mock, vi.mock)
- Coverage requirements
- File naming conventions
Example memory:
PREFERENCE: Testing style for BOOSTBOX
- Framework: Vitest
- Assertion: expect()
- Structure: describe/it blocks
- Coverage: Minimum 80%
- File naming: {filename}.test.js向上下文管理器查询:
search memories:
- Type: PREFERENCE, PROCEDURE
- Tags: testing, test-framework, test-style
- Project: current project需调取的内容:
- 测试框架(Jest、Vitest、Pytest等)
- 断言风格(expect、assert、should)
- 测试结构(describe/it、test块)
- 模拟模式(jest.mock、vi.mock)
- 覆盖率要求
- 文件命名规范
记忆示例:
PREFERENCE: Testing style for BOOSTBOX
- Framework: Vitest
- Assertion: expect()
- Structure: describe/it blocks
- Coverage: Minimum 80%
- File naming: {filename}.test.js3. Generate Test Suite
3. 生成测试套件
Unit Test Template:
javascript
import { describe, it, expect } from 'vitest';
import { calculateDiscount } from './discount';
describe('calculateDiscount', () => {
describe('basic calculations', () => {
it('should calculate discount correctly for regular customers', () => {
const result = calculateDiscount(100, 10, 'regular');
expect(result).toBe(90);
});
it('should add bonus discount for premium customers', () => {
const result = calculateDiscount(100, 10, 'premium');
expect(result).toBe(80); // 10% + 10% bonus
});
});
describe('edge cases', () => {
it('should handle zero discount', () => {
const result = calculateDiscount(100, 0, 'regular');
expect(result).toBe(100);
});
it('should handle 100% discount', () => {
const result = calculateDiscount(100, 100, 'regular');
expect(result).toBe(0);
});
it('should handle zero price', () => {
const result = calculateDiscount(0, 10, 'regular');
expect(result).toBe(0);
});
});
describe('invalid inputs', () => {
it('should handle negative price', () => {
const result = calculateDiscount(-100, 10, 'regular');
expect(result).toBeLessThan(0);
});
it('should handle invalid customer type', () => {
const result = calculateDiscount(100, 10, 'unknown');
expect(result).toBe(90); // Falls back to regular
});
});
});Integration Test Template (API endpoint):
javascript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import { app } from './app';
import { db } from './db';
describe('POST /api/users', () => {
beforeAll(async () => {
await db.connect();
});
afterAll(async () => {
await db.disconnect();
});
it('should create a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
name: 'Test User'
});
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
expect(response.body.email).toBe('test@example.com');
});
it('should reject duplicate email', async () => {
await request(app).post('/api/users').send({
email: 'duplicate@example.com',
name: 'User 1'
});
const response = await request(app)
.post('/api/users')
.send({
email: 'duplicate@example.com',
name: 'User 2'
});
expect(response.status).toBe(409);
expect(response.body.error).toContain('already exists');
});
it('should validate required fields', async () => {
const response = await request(app)
.post('/api/users')
.send({
name: 'No Email'
});
expect(response.status).toBe(400);
expect(response.body.error).toContain('email');
});
});E2E Test Template (Playwright):
javascript
import { test, expect } from '@playwright/test';
test.describe('User Login Flow', () => {
test('should login successfully with valid credentials', async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('.welcome-message')).toContainText('Welcome');
});
test('should show error with invalid credentials', async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'wrong@example.com');
await page.fill('[name="password"]', 'wrongpass');
await page.click('button[type="submit"]');
await expect(page.locator('.error-message')).toContainText('Invalid');
await expect(page).toHaveURL('/login');
});
test('should validate required fields', async ({ page }) => {
await page.goto('/login');
await page.click('button[type="submit"]');
await expect(page.locator('[name="email"]:invalid')).toBeVisible();
await expect(page.locator('[name="password"]:invalid')).toBeVisible();
});
});单元测试模板:
javascript
import { describe, it, expect } from 'vitest';
import { calculateDiscount } from './discount';
describe('calculateDiscount', () => {
describe('basic calculations', () => {
it('should calculate discount correctly for regular customers', () => {
const result = calculateDiscount(100, 10, 'regular');
expect(result).toBe(90);
});
it('should add bonus discount for premium customers', () => {
const result = calculateDiscount(100, 10, 'premium');
expect(result).toBe(80); // 10% + 10% bonus
});
});
describe('edge cases', () => {
it('should handle zero discount', () => {
const result = calculateDiscount(100, 0, 'regular');
expect(result).toBe(100);
});
it('should handle 100% discount', () => {
const result = calculateDiscount(100, 100, 'regular');
expect(result).toBe(0);
});
it('should handle zero price', () => {
const result = calculateDiscount(0, 10, 'regular');
expect(result).toBe(0);
});
});
describe('invalid inputs', () => {
it('should handle negative price', () => {
const result = calculateDiscount(-100, 10, 'regular');
expect(result).toBeLessThan(0);
});
it('should handle invalid customer type', () => {
const result = calculateDiscount(100, 10, 'unknown');
expect(result).toBe(90); // Falls back to regular
});
});
});集成测试模板(API接口):
javascript
import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import request from 'supertest';
import { app } from './app';
import { db } from './db';
describe('POST /api/users', () => {
beforeAll(async () => {
await db.connect();
});
afterAll(async () => {
await db.disconnect();
});
it('should create a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'test@example.com',
name: 'Test User'
});
expect(response.status).toBe(201);
expect(response.body).toHaveProperty('id');
expect(response.body.email).toBe('test@example.com');
});
it('should reject duplicate email', async () => {
await request(app).post('/api/users').send({
email: 'duplicate@example.com',
name: 'User 1'
});
const response = await request(app)
.post('/api/users')
.send({
email: 'duplicate@example.com',
name: 'User 2'
});
expect(response.status).toBe(409);
expect(response.body.error).toContain('already exists');
});
it('should validate required fields', async () => {
const response = await request(app)
.post('/api/users')
.send({
name: 'No Email'
});
expect(response.status).toBe(400);
expect(response.body.error).toContain('email');
});
});E2E测试模板(Playwright):
javascript
import { test, expect } from '@playwright/test';
test.describe('User Login Flow', () => {
test('should login successfully with valid credentials', async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'user@example.com');
await page.fill('[name="password"]', 'password123');
await page.click('button[type="submit"]');
await expect(page).toHaveURL('/dashboard');
await expect(page.locator('.welcome-message')).toContainText('Welcome');
});
test('should show error with invalid credentials', async ({ page }) => {
await page.goto('/login');
await page.fill('[name="email"]', 'wrong@example.com');
await page.fill('[name="password"]', 'wrongpass');
await page.click('button[type="submit"]');
await expect(page.locator('.error-message')).toContainText('Invalid');
await expect(page).toHaveURL('/login');
});
test('should validate required fields', async ({ page }) => {
await page.goto('/login');
await page.click('button[type="submit"]');
await expect(page.locator('[name="email"]:invalid')).toBeVisible();
await expect(page.locator('[name="password"]:invalid')).toBeVisible();
});
});4. Coverage Analysis
4. 覆盖率分析
Check what's tested:
javascript
// Coverage requirements (from memory or defaults)
const requirements = {
statements: 80,
branches: 75,
functions: 90,
lines: 80
};
// Identify untested scenarios
const missing = [
'Error handling for network failures',
'Loading state transitions',
'Concurrent operations',
'Cleanup on unmount'
];
// Generate additional tests for missing coverage检查测试覆盖范围:
javascript
// Coverage requirements (from memory or defaults)
const requirements = {
statements: 80,
branches: 75,
functions: 90,
lines: 80
};
// Identify untested scenarios
const missing = [
'Error handling for network failures',
'Loading state transitions',
'Concurrent operations',
'Cleanup on unmount'
];
// Generate additional tests for missing coverage5. Save Testing Patterns
5. 保存测试模式
After generating tests:
bash
undefined生成测试后:
bash
undefinedSave testing style to memory
Save testing style to memory
remember: Testing pattern for authentication
Type: PROCEDURE
Tags: testing, authentication, integration
Content: For auth endpoints, always test:
- Valid credentials → success
- Invalid credentials → 401
- Missing fields → 400
- Expired token → 401
- Token refresh flow
undefinedremember: Testing pattern for authentication
Type: PROCEDURE
Tags: testing, authentication, integration
Content: For auth endpoints, always test:
- Valid credentials → success
- Invalid credentials → 401
- Missing fields → 400
- Expired token → 401
- Token refresh flow
undefinedFramework-Specific Patterns
框架专属模式
Jest/Vitest (JavaScript/TypeScript)
Jest/Vitest(JavaScript/TypeScript)
javascript
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should do something', () => {
expect(result).toBe(expected);
});
});Mocking:
javascript
// Mock module
vi.mock('./api', () => ({
fetchData: vi.fn(() => Promise.resolve({ data: [] }))
}));
// Mock implementation
const mockFn = vi.fn().mockImplementation(() => 'value');javascript
import { describe, it, expect, vi, beforeEach } from 'vitest';
describe('Component', () => {
beforeEach(() => {
vi.clearAllMocks();
});
it('should do something', () => {
expect(result).toBe(expected);
});
});模拟操作:
javascript
// Mock module
vi.mock('./api', () => ({
fetchData: vi.fn(() => Promise.resolve({ data: [] }))
}));
// Mock implementation
const mockFn = vi.fn().mockImplementation(() => 'value');Pytest (Python)
Pytest(Python)
python
import pytest
from mymodule import calculate_discount
class TestCalculateDiscount:
def test_regular_customer(self):
result = calculate_discount(100, 10, 'regular')
assert result == 90
def test_premium_customer(self):
result = calculate_discount(100, 10, 'premium')
assert result == 80
@pytest.mark.parametrize("price,discount,expected", [
(100, 0, 100),
(100, 100, 0),
(0, 10, 0),
])
def test_edge_cases(self, price, discount, expected):
result = calculate_discount(price, discount, 'regular')
assert result == expectedFixtures:
python
@pytest.fixture
def sample_user():
return {
'id': 1,
'email': 'test@example.com',
'name': 'Test User'
}
def test_user_creation(sample_user):
assert sample_user['email'] == 'test@example.com'python
import pytest
from mymodule import calculate_discount
class TestCalculateDiscount:
def test_regular_customer(self):
result = calculate_discount(100, 10, 'regular')
assert result == 90
def test_premium_customer(self):
result = calculate_discount(100, 10, 'premium')
assert result == 80
@pytest.mark.parametrize("price,discount,expected", [
(100, 0, 100),
(100, 100, 0),
(0, 10, 0),
])
def test_edge_cases(self, price, discount, expected):
result = calculate_discount(price, discount, 'regular')
assert result == expected测试夹具:
python
@pytest.fixture
def sample_user():
return {
'id': 1,
'email': 'test@example.com',
'name': 'Test User'
}
def test_user_creation(sample_user):
assert sample_user['email'] == 'test@example.com'React Testing Library
React Testing Library
javascript
import { render, screen, fireEvent } from '@testing-library/react';
import { expect, test } from 'vitest';
import { UserList } from './UserList';
test('renders user list', () => {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
render(<UserList users={users} />);
expect(screen.getByText('Alice')).toBeInTheDocument();
expect(screen.getByText('Bob')).toBeInTheDocument();
});
test('handles empty user list', () => {
render(<UserList users={[]} />);
expect(screen.getByText('No users found')).toBeInTheDocument();
});
test('handles user click', () => {
const handleClick = vi.fn();
const users = [{ id: 1, name: 'Alice' }];
render(<UserList users={users} onUserClick={handleClick} />);
fireEvent.click(screen.getByText('Alice'));
expect(handleClick).toHaveBeenCalledWith(users[0]);
});javascript
import { render, screen, fireEvent } from '@testing-library/react';
import { expect, test } from 'vitest';
import { UserList } from './UserList';
test('renders user list', () => {
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
render(<UserList users={users} />);
expect(screen.getByText('Alice')).toBeInTheDocument();
expect(screen.getByText('Bob')).toBeInTheDocument();
});
test('handles empty user list', () => {
render(<UserList users={[]} />);
expect(screen.getByText('No users found')).toBeInTheDocument();
});
test('handles user click', () => {
const handleClick = vi.fn();
const users = [{ id: 1, name: 'Alice' }];
render(<UserList users={users} onUserClick={handleClick} />);
fireEvent.click(screen.getByText('Alice'));
expect(handleClick).toHaveBeenCalledWith(users[0]);
});Test Categories
测试分类
Unit Tests
单元测试
What to test:
- Pure functions
- Utility functions
- Component logic
- Class methods
Focus on:
- Input/output correctness
- Edge cases
- Error conditions
- Boundary values
测试对象:
- 纯函数
- 工具函数
- 组件逻辑
- 类方法
测试重点:
- 输入输出正确性
- 边缘场景
- 错误情况
- 边界值
Integration Tests
集成测试
What to test:
- API endpoints
- Database operations
- Multiple components together
- External service integration
Focus on:
- Component interactions
- Data flow
- Error propagation
- Transaction handling
测试对象:
- API接口
- 数据库操作
- 多组件协作
- 外部服务集成
测试重点:
- 组件交互
- 数据流
- 错误传播
- 事务处理
E2E Tests
E2E测试
What to test:
- Critical user flows
- Complete features
- Multi-step processes
- Cross-page workflows
Focus on:
- User perspective
- Real browser interaction
- Full stack integration
- Production-like environment
测试对象:
- 关键用户流程
- 完整功能
- 多步骤流程
- 跨页面工作流
测试重点:
- 用户视角
- 真实浏览器交互
- 全栈集成
- 类生产环境
Regression Tests
回归测试
When to create:
- After fixing a bug
- Preventing known issues
- Historical problems
Structure:
javascript
describe('Regression: Bug #123 - User map undefined', () => {
it('should handle undefined users array', () => {
// Test that previously failed
const result = renderUserList(undefined);
expect(result).not.toThrow();
});
});创建时机:
- 修复漏洞后
- 预防已知问题
- 历史故障
结构示例:
javascript
describe('Regression: Bug #123 - User map undefined', () => {
it('should handle undefined users array', () => {
// Test that previously failed
const result = renderUserList(undefined);
expect(result).not.toThrow();
});
});Context Integration
上下文集成
Recall Testing Preferences
调取测试偏好
Before generating tests:
javascript
// Query context-manager
const preferences = searchMemories({
type: 'PREFERENCE',
tags: ['testing', project],
recent: true
});
// Apply preferences
const testConfig = {
framework: preferences.framework || 'vitest',
style: preferences.style || 'describe/it',
coverage: preferences.coverage || 80,
naming: preferences.naming || '{name}.test.js'
};生成测试前:
javascript
// Query context-manager
const preferences = searchMemories({
type: 'PREFERENCE',
tags: ['testing', project],
recent: true
});
// Apply preferences
const testConfig = {
framework: preferences.framework || 'vitest',
style: preferences.style || 'describe/it',
coverage: preferences.coverage || 80,
naming: preferences.naming || '{name}.test.js'
};Save Testing Patterns
保存测试模式
After generating tests:
bash
remember: Testing pattern for API endpoints
Type: PROCEDURE
Tags: testing, api, integration
Content: For API endpoints, always include:
1. Happy path (200/201)
2. Validation errors (400)
3. Auth errors (401/403)
4. Not found (404)
5. Server errors (500)
6. Rate limiting (429)生成测试后:
bash
remember: Testing pattern for API endpoints
Type: PROCEDURE
Tags: testing, api, integration
Content: For API endpoints, always include:
1. Happy path (200/201)
2. Validation errors (400)
3. Auth errors (401/403)
4. Not found (404)
5. Server errors (500)
6. Rate limiting (429)Learn from Feedback
从反馈中学习
If user modifies generated tests:
javascript
// Analyze what user changed
const changes = diff(generatedTest, userModifiedTest);
// Save as new pattern if significant
if (changes.significant) {
saveMemory({
type: 'PREFERENCE',
content: `User prefers ${changes.pattern}`,
tags: ['testing', 'user-preference']
});
}如果用户修改了生成的测试:
javascript
// Analyze what user changed
const changes = diff(generatedTest, userModifiedTest);
// Save as new pattern if significant
if (changes.significant) {
saveMemory({
type: 'PREFERENCE',
content: `User prefers ${changes.pattern}`,
tags: ['testing', 'user-preference']
});
}Integration with Other Skills
与其他功能集成
Error Debugger
错误调试工具
When error-debugger fixes a bug:
Automatically invoke testing-builder
Create regression test for: {bug_scenario}
Ensure test fails before fix, passes after当错误调试工具修复漏洞时:
自动调用测试构建工具
为以下场景创建回归测试:{bug_scenario}
确保测试在修复前失败,修复后通过Context Manager
上下文管理器
Load testing preferences:
Query for PREFERENCE with tags: [testing, test-framework]
Apply framework, style, coverage preferencesSave new patterns:
After generating tests for new scenario
Save pattern as PROCEDURE for future reference加载测试偏好:
查询标签为[testing, test-framework]的PREFERENCE类型内容
应用框架、风格、覆盖率偏好设置保存新模式:
为新场景生成测试后
将模式保存为PROCEDURE类型以供后续参考Code Quality Auditor
代码质量审计工具
Check test quality:
After generating tests:
→ Invoke code-quality-auditor
→ Verify test coverage
→ Check for test smells
→ Ensure meaningful assertions检查测试质量:
生成测试后:
→ 调用代码质量审计工具
→ 验证测试覆盖率
→ 检查测试冗余
→ 确保断言有意义Quick Reference
快速参考
Test Generation Checklist
测试生成检查清单
✅ Happy path covered
✅ Edge cases tested
✅ Error conditions handled
✅ Invalid inputs validated
✅ Boundary values checked
✅ Async operations handled
✅ Mocks properly configured
✅ Cleanup properly done
✅ Assertions are meaningful
✅ 覆盖正常流程
✅ 测试边缘场景
✅ 处理错误情况
✅ 验证无效输入
✅ 检查边界值
✅ 处理异步操作
✅ 正确配置模拟
✅ 完成清理操作
✅ 断言具有意义
Common Test Patterns
常见测试模式
| Scenario | Pattern |
|---|---|
| Function | Input → Output assertions |
| Component | Render → Query → Assert |
| API | Request → Response → Assert |
| Async | await → Promise → Result |
| Error | Try/catch → Error assertion |
| Mock | Setup → Call → Verify mock |
| 场景 | 模式 |
|---|---|
| 函数 | 输入 → 输出断言 |
| 组件 | 渲染 → 查询 → 断言 |
| API | 请求 → 响应 → 断言 |
| 异步操作 | await → Promise → 结果 |
| 错误处理 | Try/catch → 错误断言 |
| 模拟操作 | 配置 → 调用 → 验证模拟 |
Trigger Phrases
触发短语
- "write tests"
- "test this"
- "add coverage"
- "create regression test"
- "needs tests"
- "write tests"
- "test this"
- "add coverage"
- "create regression test"
- "needs tests"
File Locations
文件位置
- Test patterns: (tagged "testing")
~/.claude-memories/ (Linux/macOS) or %USERPROFILE%\.claude-memories\ (Windows)procedures/ - Test preferences: (tagged "testing")
~/.claude-memories/ (Linux/macOS) or %USERPROFILE%\.claude-memories\ (Windows)preferences/ - Generated tests: or
{filename}.test.{ext}tests/{filename}.test.{ext}
- 测试模式:(标记为"testing")
~/.claude-memories/ (Linux/macOS) 或 %USERPROFILE%\.claude-memories\ (Windows)procedures/ - 测试偏好:(标记为"testing")
~/.claude-memories/ (Linux/macOS) 或 %USERPROFILE%\.claude-memories\ (Windows)preferences/ - 生成的测试:或
{filename}.test.{ext}tests/{filename}.test.{ext}
Success Criteria
成功标准
✅ Tests generated in <30 seconds
✅ Comprehensive coverage (80%+ by default)
✅ All edge cases included
✅ Tests follow project style
✅ Zero manual effort required
✅ Testing patterns saved for future
✅ 测试生成时间<30秒
✅ 全面覆盖(默认80%+)
✅ 包含所有边缘场景
✅ 符合项目测试风格
✅ 无需手动操作
✅ 保存测试模式以供后续使用