You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
6.2 KiB
6.2 KiB
测试目录结构重构
日期: 2026-01-27
类型: 重构
影响范围: 测试代码组织
背景
项目根目录下的 test_sms_service.py 和 test_wechat_service.py 是集成测试脚本,但位置和组织方式不符合标准测试规范:
- ❌ 位于项目根目录,不易管理
- ❌ 未使用 pytest 框架
- ❌ 缺少测试分类(单元测试 vs 集成测试)
- ❌ 缺少共享 fixtures 和配置
解决方案
1. 创建标准测试目录结构
server/
├── pytest.ini # pytest 配置文件
└── tests/
├── __init__.py # 测试模块初始化
├── conftest.py # pytest 配置和共享 fixtures
├── README.md # 测试文档
├── integration/ # 集成测试
│ ├── __init__.py
│ ├── test_sms_service.py
│ └── test_wechat_service.py
└── unit/ # 单元测试(预留)
└── __init__.py
2. 配置 pytest
pytest.ini:
[pytest]
testpaths = tests
python_files = test_*.py
asyncio_mode = auto
log_cli = true
log_cli_level = INFO
markers =
integration: 集成测试(需要真实数据库、Redis)
unit: 单元测试(使用 Mock)
slow: 慢速测试
3. 创建共享 Fixtures
conftest.py:
@pytest.fixture
async def db_session(engine) -> AsyncGenerator[AsyncSession, None]:
"""创建数据库会话(自动回滚)"""
async_session = sessionmaker(
engine,
class_=AsyncSession,
expire_on_commit=False
)
async with async_session() as session:
yield session
await session.rollback()
@pytest.fixture
async def redis_client() -> AsyncGenerator[Redis, None]:
"""创建 Redis 客户端(自动清理)"""
client = Redis.from_url(settings.REDIS_URL)
yield client
await client.flushdb()
await client.close()
4. 重构测试文件
改进点:
- ✅ 使用 pytest 装饰器(
@pytest.mark.asyncio,@pytest.mark.integration) - ✅ 使用共享 fixtures(
db_session,redis_client) - ✅ 拆分为独立的测试函数
- ✅ 添加断言和异常测试
- ✅ 保留直接运行支持(兼容旧方式)
示例:
@pytest.mark.integration
@pytest.mark.asyncio
async def test_send_verification_code(db_session):
"""测试发送验证码"""
sms_service = SmsService(db_session)
result = await sms_service.send_verification_code(
phone="15980906230",
country_code="+86",
purpose=SmsPurpose.LOGIN,
ip_address="127.0.0.1"
)
assert result is not None
assert "message" in result
assert result["expiresIn"] == 600
修改文件
创建
server/pytest.ini- pytest 配置server/tests/__init__.py- 测试模块初始化server/tests/conftest.py- 共享 fixturesserver/tests/README.md- 测试文档server/tests/integration/__init__.py- 集成测试模块server/tests/integration/test_sms_service.py- 短信服务测试(重构)server/tests/integration/test_wechat_service.py- 微信服务测试(重构)server/tests/unit/__init__.py- 单元测试模块(预留)
删除
server/test_sms_service.py- 已移动到tests/integration/server/test_wechat_service.py- 已移动到tests/integration/
运行测试
使用 pytest(推荐)
# 运行所有测试
pytest tests/ -v
# 仅运行集成测试
pytest tests/integration/ -v
# 运行特定测试文件
pytest tests/integration/test_sms_service.py -v
# 运行特定测试函数
pytest tests/integration/test_sms_service.py::test_send_verification_code -v
# 显示打印输出
pytest tests/ -v -s
# 使用标记
pytest -m integration # 仅集成测试
pytest -m "not slow" # 跳过慢速测试
直接运行(兼容旧方式)
# 仍然支持直接运行
python tests/integration/test_sms_service.py
python tests/integration/test_wechat_service.py
测试分类
集成测试(Integration Tests)
- 位置:
tests/integration/ - 特点: 使用真实数据库、Redis
- 用途: 验证完整业务流程
- 标记:
@pytest.mark.integration
现有测试:
test_sms_service.py- 短信发送、验证、防刷、清理test_wechat_service.py- 二维码生成、登录、绑定、解绑
单元测试(Unit Tests)
- 位置:
tests/unit/(预留) - 特点: 使用 Mock/Stub,不依赖外部服务
- 用途: 测试单个函数或类的逻辑
- 标记:
@pytest.mark.unit
未来计划:
- Service 层业务逻辑测试
- Repository 层数据访问测试
- Utils 工具函数测试
环境要求
集成测试
需要以下服务运行:
# 启动数据库和 Redis
docker-compose up -d jointo-server-db jointo-server-redis
# 运行数据库迁移
docker exec jointo-server-app alembic upgrade head
# 运行测试
pytest tests/integration/ -v
单元测试
不依赖外部服务,可以直接运行:
pytest tests/unit/ -v
优势
1. 标准化
- ✅ 符合 pytest 最佳实践
- ✅ 清晰的目录结构
- ✅ 统一的测试规范
2. 可维护性
- ✅ 共享 fixtures 减少重复代码
- ✅ 独立的测试函数便于调试
- ✅ 清晰的测试分类
3. 可扩展性
- ✅ 预留单元测试目录
- ✅ 支持自定义标记
- ✅ 易于添加新测试
4. CI/CD 友好
- ✅ 标准的 pytest 命令
- ✅ 支持覆盖率报告
- ✅ 支持并行测试
后续计划
-
添加单元测试
- Service 层业务逻辑测试
- Repository 层数据访问测试
- Utils 工具函数测试
-
添加 API 测试
- 使用 TestClient 测试 FastAPI 路由
- 测试请求/响应格式
- 测试认证和权限
-
添加性能测试
- 使用 pytest-benchmark
- 测试关键接口性能
- 监控性能回归
-
集成 CI/CD
- GitHub Actions 自动运行测试
- 生成覆盖率报告
- 测试失败时阻止合并