E2E 测试文档
本文档介绍 MBE 项目的端到端(E2E)测试实现和使用方法。
概述
E2E 测试覆盖完整的用户流程,从用户注册到 API 调用,再到错误处理。这些测试确保整个系统在真实场景下能够正常工作。
测试文件结构
tests/e2e/
├── __init__.py
├── test_user_e2e_workflow.py # 完整用户流程测试
├── test_api_e2e_workflow.py # API 调用完整流程测试
└── test_error_handling_e2e.py # 错误处理流程测试
测试覆盖范围
1. 用户端到端流程 (test_user_e2e_workflow.py)
测试场景
完整用户流程 (
test_complete_user_workflow)- 用户注册(在 fixture 中完成)
- 用户登录
- 获取用户信息
- 获取 Token 余额
- 使用 API(调用专家)
- 查看使用统计
- 刷新 Token
Token 购买和使用流程 (
test_token_purchase_and_usage_workflow)- 查看当前余额
- 创建 Token 购买订单
- 查看订单状态
- 使用 Token
- 查看使用后的余额
订阅管理流程 (
test_subscription_management_workflow)- 查看当前订阅
- 升级订阅(如果支持)
- 查看订阅详情
- 查看订阅使用统计
错误处理流程 (
test_error_handling_workflow)- 使用错误密码登录
- 使用无效 Token 访问受保护端点
- 访问不存在的资源
- 使用无效参数调用 API
API 调用完整流程 (
test_api_call_complete_workflow)- 获取 API Key(如果支持)
- 使用 API Key 调用 API
- 查看 API 调用历史
- 查看 API 使用统计
设备绑定流程 (
test_device_binding_workflow)- 绑定设备
- 查看设备列表
- 解绑设备(如果支持)
用户资料更新流程 (
test_user_profile_update_workflow)- 获取当前用户信息
- 更新用户信息
- 验证更新成功
2. API 调用完整流程 (test_api_e2e_workflow.py)
测试场景
API 认证流程 (
test_api_authentication_flow)- 未认证访问受保护端点(应失败)
- 注册并获取 Token
- 使用 Token 访问受保护端点(应成功)
- Token 过期处理(如果可能)
API 速率限制 (
test_api_rate_limiting)- 快速连续调用 API
- 验证速率限制生效
- 等待后重试
API 错误响应 (
test_api_error_responses)- 400 Bad Request(无效参数)
- 404 Not Found(资源不存在)
- 422 Unprocessable Entity(验证错误)
API 响应格式 (
test_api_response_format)- 成功响应格式
- 错误响应格式
- 分页响应格式(如果适用)
API 并发请求 (
test_api_concurrent_requests)- 同时发送多个请求
- 验证所有请求都能正确处理
API CORS 头 (
test_api_cors_headers)- OPTIONS 预检请求
- 验证 CORS 头存在
3. 错误处理流程 (test_error_handling_e2e.py)
测试场景
认证错误 (
test_authentication_errors)- 无效 Token
- 过期 Token(如果可能)
- 缺失 Token
- 错误格式的 Token
验证错误 (
test_validation_errors)- 无效邮箱格式
- 密码太短
- 缺失必填字段
- 类型错误
404 错误 (
test_not_found_errors)- 不存在的用户
- 不存在的资源
- 不存在的端点
重复资源错误 (
test_duplicate_resource_errors)- 重复邮箱注册
- 重复设备绑定(如果适用)
权限错误 (
test_permission_errors)- 普通用户访问管理员端点
- 未授权访问受保护资源
速率限制错误 (
test_rate_limit_errors)- 快速连续请求
- 验证 429 响应
- 验证重试机制
格式错误请求 (
test_malformed_request_errors)- 无效 JSON
- 缺失 Content-Type
- 无效的 HTTP 方法
错误响应格式 (
test_error_response_format)- 所有错误都应该有 detail 或 message 字段
- 错误响应格式应该一致
运行测试
运行所有 E2E 测试
# 运行所有 E2E 测试
pytest tests/e2e/ -v -m e2e
# 运行所有 E2E 测试(包括集成测试标记)
pytest tests/e2e/ -v -m "e2e or integration"
运行特定测试文件
# 运行用户流程测试
pytest tests/e2e/test_user_e2e_workflow.py -v
# 运行 API 流程测试
pytest tests/e2e/test_api_e2e_workflow.py -v
# 运行错误处理测试
pytest tests/e2e/test_error_handling_e2e.py -v
运行特定测试场景
# 运行完整用户流程测试
pytest tests/e2e/test_user_e2e_workflow.py::TestUserE2EWorkflow::test_complete_user_workflow -v
# 运行 Token 购买和使用流程测试
pytest tests/e2e/test_user_e2e_workflow.py::TestUserE2EWorkflow::test_token_purchase_and_usage_workflow -v
测试依赖
E2E 测试需要以下依赖:
pytest- 测试框架pytest-asyncio- 异步测试支持httpx- HTTP 测试客户端
这些依赖已在 tests/requirements.txt 中定义。
测试 Fixtures
registered_user
自动注册用户并返回认证信息:
@pytest.fixture
async def registered_user(client, test_email, test_password):
# 注册用户并返回认证信息
return {
"user_id": ...,
"email": ...,
"access_token": ...,
"refresh_token": ...
}
authenticated_client
创建已认证的测试客户端:
@pytest.fixture
async def authenticated_client(client):
# 注册用户并设置认证头
client.headers.update({"Authorization": f"Bearer {access_token}"})
yield client
测试数据管理
自动清理
测试使用 clean_db fixture 自动清理测试数据:
- 测试用户(email 以
test@开头) - 测试设备(device_id 以
test-开头) - 关联的 Token 余额和订阅数据
唯一测试数据
每个测试使用时间戳生成唯一的测试数据:
test_email = f"e2e-test-{int(time.time() * 1000)}@mbe-test.com"
这确保测试之间不会相互干扰。
跳过条件
某些测试可能会跳过,如果:
- 功能不可用:如果某个功能端点不存在或不可用,测试会跳过
- 服务不可用:如果依赖的服务(如专家服务)不可用,测试会跳过
- 环境限制:如果测试环境不支持某些功能,测试会跳过
跳过时会显示原因:
pytest.skip(f"专家服务不可用: {e}")
最佳实践
1. 测试隔离
每个测试都是独立的,不依赖其他测试的状态:
- 使用唯一的测试数据(时间戳)
- 自动清理测试数据
- 不共享测试状态
2. 错误处理
测试应该验证错误情况:
- 无效输入应该返回适当的错误码
- 错误响应应该有正确的格式
- 错误消息应该清晰明确
3. 可读性
测试应该清晰易懂:
- 使用描述性的测试名称
- 添加注释说明测试目的
- 使用有意义的变量名
4. 性能
E2E 测试可能较慢,应该:
- 避免不必要的等待
- 使用并发测试(如果可能)
- 标记慢速测试(
@pytest.mark.slow)
持续集成
E2E 测试应该在 CI/CD 流程中运行:
# .github/workflows/test.yml
- name: Run E2E Tests
run: |
pytest tests/e2e/ -v -m e2e
故障排查
常见问题
数据库连接错误
- 确保数据库服务正在运行
- 检查数据库连接配置
Redis 连接错误
- 确保 Redis 服务正在运行
- 检查 Redis 连接配置
测试超时
- 增加测试超时时间
- 检查是否有长时间运行的测试
事件循环错误
- 确保使用
pytest-asyncio的auto模式 - 检查 fixture 的事件循环配置
- 确保使用
扩展测试
添加新的 E2E 测试
- 在
tests/e2e/目录下创建新的测试文件 - 使用
@pytest.mark.e2e标记测试类 - 使用
@pytest.mark.integration标记需要集成测试的测试 - 使用
@pytest.mark.asyncio标记异步测试
示例:
@pytest.mark.e2e
@pytest.mark.integration
class TestNewFeatureE2E:
@pytest.mark.asyncio
async def test_new_feature_workflow(self, client: AsyncClient):
# 测试实现
pass