name: 测试 description: 跨所有领域的综合测试实施,包括单元测试、集成测试、端到端测试、安全测试、基础设施测试、数据管道测试和机器学习模型测试。覆盖TDD/BDD工作流、测试架构、不稳定测试调试和覆盖率分析。 allowed-tools: 读取、搜索、全局、编辑、写入、Bash trigger-keywords: 测试、测试、规格、断言、期望、模拟、存根、间谍、夹具、快照、覆盖率、TDD、BDD、红绿、回归、单元测试、集成测试、端到端、测试套件、测试用例、pytest、jest、vitest、mocha、junit、testify、测试框架
测试
概述
此技能提供全面的测试专业知识,涵盖所有领域和测试类型。无论是编写单元测试、调试不稳定测试、设计测试架构,还是测试数据管道和机器学习模型等专业系统,此技能都指导测试实施,遵循行业最佳实践。
何时使用
- 为任何代码库实施测试(单元测试、集成测试、端到端测试)
- 调试不稳定或失败的测试
- 提高测试覆盖率
- 设置测试基础设施和框架
- 遵循TDD/BDD工作流
- 测试专业领域(数据、机器学习、基础设施、安全)
- 设计测试架构和策略
核心指令
1. 分析要测试的代码
- 识别公共接口和API
- 映射依赖关系和副作用
- 找到边缘情况和边界条件
- 理解预期行为和不变性
- 审查错误处理路径
- 记录假设和前提条件
2. 设计测试策略
测试金字塔方法:
- 单元测试(70%):快速、隔离,测试单个单元
- 集成测试(20%):测试组件交互
- 端到端测试(10%):测试完整用户工作流
规划:
- 为每个组件确定适当的测试类型
- 设置覆盖率目标(目标80%+行覆盖率,100%关键路径)
- 识别模拟需求和边界
- 规划测试夹具和数据管理
- 考虑性能和稳定性风险
3. 遵循AAA模式编写测试
安排-行动-断言(Arrange-Act-Assert):
- 安排:设置测试数据、模拟和条件
- 行动:执行被测试代码
- 断言:验证预期结果,并提供清晰的失败消息
命名约定:
test_<单元>_<场景>_<预期结果>
示例:test_shopping_cart_add_duplicate_item_increases_quantity
4. 处理特殊情况
异步操作:
- 使用适当的异步测试工具(async/await、done回调)
- 设置适当的超时
- 测试竞争条件和时序问题
错误条件:
- 显式测试所有错误路径
- 验证错误消息和类型
- 测试恢复机制
外部依赖:
- 模拟HTTP客户端、数据库、文件系统
- 使用测试替身(模拟、存根、伪造)
- 考虑API的契约测试
数据库测试:
- 使用事务和回滚进行隔离
- 使用内存数据库以提高速度
- 一致地播种测试数据
领域特定测试
数据管道测试
数据质量测试:
- 模式验证(列类型、可空性、约束)
- 数据完整性(行计数、空检查)
- 数据准确性(统计检查、业务规则验证)
- 数据新鲜度(时间戳检查)
管道测试:
- 幂等性:运行两次产生相同结果
- 增量处理:仅处理新数据
- 故障恢复:优雅处理部分故障
- 性能:处理时间在SLA内
示例:
def test_etl_pipeline_preserves_row_count():
# 安排
input_data = load_fixture("sales_data_1000_rows.csv")
# 行动
result = etl_pipeline.transform(input_data)
# 断言
assert len(result) == 1000, "ETL不应丢弃行"
assert result['customer_id'].notna().all(), "customer_id必填"
ML模型测试
模型行为测试:
- 不变性测试:预测在不相关变化下保持稳定
- 方向性期望:特征变化正确影响预测
- 最小功能:模型在关键示例上优于基线
数据测试:
- 训练/验证分割完整性
- 特征分布对齐
- 标签平衡和质量
性能测试:
- 测试集上的准确率/精确率/召回率
- 推断延迟要求
- 资源使用(内存、CPU)
示例:
def test_sentiment_model_invariance_to_punctuation():
model = load_model("sentiment_classifier")
text_base = "This product is amazing"
text_with_punct = "This product is amazing!!!"
pred_base = model.predict(text_base)
pred_punct = model.predict(text_with_punct)
assert abs(pred_base - pred_punct) < 0.1, \
"标点不应显著改变情感"
基础设施测试
基础设施即代码测试:
- 语法验证(terraform validate、yaml lint)
- 策略合规性(安全组、IAM策略)
- 资源标记和命名约定
- 成本估算阈值
集成测试:
- 部署冒烟测试
- 健康检查端点
- 服务连通性
- 配置验证
示例:
def test_terraform_no_public_s3_buckets():
tf_plan = load_terraform_plan("main.tfplan.json")
for resource in tf_plan.get_resources("aws_s3_bucket"):
acl = resource.get("acl", "private")
assert acl != "public-read", \
f"S3桶 {resource['name']} 必须不是公共的"
最佳实践
测试质量
- 测试一件事:每个测试验证单个行为或条件
- 描述性名称:测试名称描述场景和预期结果
- 独立测试:测试间无共享状态,可任意顺序执行
- 快速执行:单元测试 < 100ms,集成测试 < 5s
- 确定性:相同输入总是产生相同结果(无随机数据)
- 避免测试逻辑:测试应是简单断言,不是算法
- 测试边缘情况:边界条件、空输入、最大值、null
- 可读断言:使用清晰的断言消息以便调试
测试覆盖率
- 目标80%+行覆盖率,关键路径100%
- 关注行为覆盖率,而不仅是行覆盖率
- 使用覆盖率工具查找未测试代码
- 优先测试业务逻辑和错误路径
调试不稳定测试
常见原因:
- 竞争条件和时序依赖
- 测试间共享可变状态
- 外部服务依赖
- 非确定性输入(时间戳、随机值)
- 测试执行顺序依赖
解决方案:
- 添加显式等待而不是sleep
- 在设置/清理中重置状态
- 模拟外部依赖
- 使用固定种子进行随机生成
- 隔离运行测试以识别顺序依赖
TDD工作流
红绿重构循环:
- 红:为期望行为编写失败测试
- 绿:编写最小代码使测试通过
- 重构:改进代码,同时保持测试通过
好处:
- 强制在实施前思考设计
- 确保测试实际捕捉失败
- 提供快速反馈循环
- 创建全面的测试套件
框架特定模式
Python (pytest)
import pytest
from unittest.mock import Mock, patch
@pytest.fixture
def database():
db = Database()
db.connect()
yield db
db.disconnect()
@pytest.mark.parametrize("input,expected", [
(0, 0),
(1, 1),
(5, 120),
])
def test_factorial(input, expected):
assert factorial(input) == expected
@patch('requests.get')
def test_api_client(mock_get):
mock_get.return_value.json.return_value = {"status": "ok"}
result = fetch_status()
assert result == "ok"
JavaScript (Vitest/Jest)
import { describe, it, expect, vi, beforeEach } from "vitest";
describe("UserService", () => {
let mockDb;
beforeEach(() => {
mockDb = {
query: vi.fn(),
};
});
it("finds user by email", async () => {
mockDb.query.mockResolvedValue([{ id: 1, email: "test@example.com" }]);
const service = new UserService(mockDb);
const user = await service.findByEmail("test@example.com");
expect(user.id).toBe(1);
expect(mockDb.query).toHaveBeenCalledWith(
"SELECT * FROM users WHERE email = ?",
["test@example.com"],
);
});
});
Rust (built-in + mockall)
#[cfg(test)]
mod tests {
use super::*;
use mockall::predicate::*;
use mockall::mock;
mock! {
Database {}
impl DatabaseTrait for Database {
fn get_user(&self, id: i64) -> Result<User, Error>;
}
}
#[test]
fn test_user_service_fetches_from_db() {
let mut mock_db = MockDatabase::new();
mock_db
.expect_get_user()
.with(eq(1))
.return_once(|_| Ok(User { id: 1, name: "Alice".into() }));
let service = UserService::new(mock_db);
let user = service.get_user(1).unwrap();
assert_eq!(user.name, "Alice");
}
}
应避免的反模式
- 测试依赖性:测试必须按特定顺序运行
- 测试实现:测试私有方法或内部状态
- 过度模拟:模拟一切使测试脆弱
- 断言轮盘:一个测试中有多个不相关的断言
- 隐藏依赖:测试依赖外部文件或服务
- 慢测试:由于真实I/O导致测试需要几秒钟运行
- 脆弱测试:轻微重构就会破坏的测试
- 重复逻辑:将生产代码复制到测试中
测试架构
测试组织
tests/
├── unit/ # 快速、隔离的单元测试
│ ├── models/
│ ├── services/
│ └── utils/
├── integration/ # 组件交互测试
│ ├── api/
│ ├── database/
│ └── external_services/
├── e2e/ # 完整工作流测试
│ └── user_scenarios/
├── fixtures/ # 共享测试数据
└── helpers/ # 测试工具
持续集成
- 每次提交运行单元测试
- PR上运行集成测试
- 部署前运行端到端测试
- 覆盖率下降时构建失败
- 并行化测试执行
- 报告不稳定测试以供调查
示例
示例1:带模拟的单元测试
from unittest.mock import Mock, patch
import pytest
from payment_processor import PaymentProcessor
class TestPaymentProcessor:
@patch('payment_processor.stripe')
def test_successful_payment_creates_charge(self, mock_stripe):
# 安排
mock_stripe.Charge.create.return_value = Mock(
id='ch_123',
status='succeeded'
)
processor = PaymentProcessor(api_key='test_key')
# 行动
result = processor.charge(amount=1000, token='tok_visa')
# 断言
assert result.success is True
assert result.charge_id == 'ch_123'
mock_stripe.Charge.create.assert_called_once_with(
amount=1000,
currency='usd',
source='tok_visa'
)
@patch('payment_processor.stripe')
def test_declined_payment_raises_payment_error(self, mock_stripe):
# 安排
mock_stripe.Charge.create.side_effect = Exception("Card declined")
processor = PaymentProcessor(api_key='test_key')
# 行动 & 断言
with pytest.raises(PaymentError) as exc_info:
processor.charge(amount=1000, token='tok_declined')
assert "Card declined" in str(exc_info.value)
示例2:带数据库的集成测试
import { describe, it, expect, beforeEach, afterEach } from "vitest";
import { createServer } from "../server";
import { db } from "../database";
describe("User API Integration", () => {
let server;
beforeEach(async () => {
server = await createServer();
await db.migrate.latest();
await db.seed.run();
});
afterEach(async () => {
await db.migrate.rollback();
await server.close();
});
it("creates user and returns 201 with user data", async () => {
const response = await server.inject({
method: "POST",
url: "/api/users",
payload: {
email: "new@example.com",
name: "New User",
},
});
expect(response.statusCode).toBe(201);
expect(response.json()).toMatchObject({
email: "new@example.com",
name: "New User",
});
// 验证数据库状态
const user = await db("users").where({ email: "new@example.com" }).first();
expect(user).toBeDefined();
});
it("returns 400 for invalid email format", async () => {
const response = await server.inject({
method: "POST",
url: "/api/users",
payload: {
email: "invalid-email",
name: "Test User",
},
});
expect(response.statusCode).toBe(400);
expect(response.json().error).toContain("email");
});
});
示例3:快照测试
import { render } from "@testing-library/react";
import { UserCard } from "./UserCard";
it("renders user card correctly", () => {
const user = {
id: 1,
name: "Alice",
email: "alice@example.com",
avatar: "/avatars/alice.jpg",
};
const { container } = render(<UserCard user={user} />);
// UI组件的快照测试
expect(container.firstChild).toMatchSnapshot();
});
总结
此技能提供全面的测试专业知识,涵盖:
- 所有测试类型(单元测试、集成测试、端到端测试)
- 所有领域(后端、前端、数据、机器学习、基础设施)
- 测试架构和策略
- 调试和维护
- TDD/BDD工作流
目标是生产质量的测试,以捕捉错误、记录行为并支持自信的重构。