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.
11 KiB
11 KiB
项目服务测试指南
创建日期:2026-01-29
测试覆盖:项目管理服务完整测试套件
测试概述
项目服务测试套件包含三个层次的测试:
- 单元测试:测试仓储层和服务层的独立功能
- 集成测试:测试 API 层与数据库的集成
- 端到端测试:测试完整的用户场景(待实现)
测试文件结构
server/tests/
├── unit/
│ ├── test_project_repository.py # 仓储层单元测试
│ └── test_project_service.py # 服务层单元测试
├── integration/
│ └── test_project_api.py # API 集成测试
└── conftest.py # 测试配置和 fixtures
运行测试
运行所有测试
# 在容器内运行
docker exec jointo-server-app pytest
# 或使用 pytest 标记
docker exec jointo-server-app pytest -v
运行特定测试文件
# 仓储层测试
docker exec jointo-server-app pytest tests/unit/test_project_repository.py -v
# 服务层测试
docker exec jointo-server-app pytest tests/unit/test_project_service.py -v
# API 集成测试
docker exec jointo-server-app pytest tests/integration/test_project_api.py -v
运行特定测试类或方法
# 运行特定测试类
docker exec jointo-server-app pytest tests/unit/test_project_repository.py::TestProjectRepository -v
# 运行特定测试方法
docker exec jointo-server-app pytest tests/unit/test_project_repository.py::TestProjectRepository::test_create_project -v
生成测试覆盖率报告
# 生成覆盖率报告
docker exec jointo-server-app pytest --cov=app.repositories.project_repository --cov=app.services.project_service --cov=app.api.v1.projects --cov-report=html
# 查看覆盖率报告
open server/htmlcov/index.html
测试覆盖范围
1. 仓储层测试(test_project_repository.py)
基础 CRUD:
- ✅
test_create_project- 创建项目 - ✅
test_get_by_id- 通过 ID 查询 - ✅
test_get_by_id_not_found- 查询不存在的项目 - ✅
test_update_project- 更新项目
回收站管理:
- ✅
test_move_to_trash- 移至回收站 - ✅
test_restore_from_trash- 从回收站恢复 - ✅
test_permanent_delete- 永久删除
查询方法:
- ✅
test_get_by_user- 获取用户项目列表 - ✅
test_get_by_user_with_filters- 带筛选条件的查询 - ✅
test_count_by_user- 统计用户项目数量 - ✅
test_exists_by_name- 检查名称唯一性
权限管理:
- ✅
test_check_user_permission_owner- 检查所有者权限 - ✅
test_check_user_permission_no_access- 检查无权限用户
成员管理:
- ✅
test_add_member- 添加成员 - ✅
test_get_members- 获取成员列表 - ✅
test_remove_member- 移除成员
分享管理:
- ✅
test_create_share- 创建分享 - ✅
test_get_shares- 获取分享列表 - ✅
test_get_share_by_token- 通过 token 获取分享 - ✅
test_delete_share- 删除分享
其他功能:
- ✅
test_move_to_folder- 移动项目 - ✅
test_clone_project- 克隆项目
2. 服务层测试(test_project_service.py)
项目管理:
- ✅
test_get_projects_success- 获取项目列表成功 - ✅
test_get_projects_invalid_sort_field- 无效排序字段 - ✅
test_get_projects_invalid_sort_order- 无效排序方向 - ✅
test_get_project_success- 获取项目详情成功 - ✅
test_get_project_not_found- 项目不存在 - ✅
test_get_project_no_permission- 无权限访问 - ✅
test_create_project_success- 创建项目成功 - ✅
test_create_project_duplicate_name- 重名项目 - ✅
test_update_project_success- 更新项目成功 - ✅
test_delete_project_success- 删除项目成功 - ✅
test_delete_project_not_owner- 非所有者删除
回收站管理:
- ✅
test_restore_project_success- 恢复项目成功 - ✅
test_restore_project_not_in_trash- 恢复非回收站项目 - ✅
test_permanent_delete_success- 永久删除成功
成员管理:
- ✅
test_add_member_success- 添加成员成功 - ✅
test_add_member_already_exists- 添加已存在的成员 - ✅
test_remove_member_success- 移除成员成功 - ✅
test_remove_member_self- 移除自己
分享管理:
- ✅
test_create_share_success- 创建分享成功 - ✅
test_revoke_share_success- 撤销分享成功
其他功能:
- ✅
test_clone_project_success- 克隆项目成功 - ✅
test_export_project_placeholder- 导出项目(占位)
3. API 集成测试(test_project_api.py)
项目列表:
- ✅
test_get_projects_success- 获取列表成功 - ✅
test_get_projects_with_filters- 带筛选条件 - ✅
test_get_projects_pagination- 分页 - ✅
test_get_projects_unauthorized- 未认证访问
创建项目:
- ✅
test_create_project_success- 创建成功 - ✅
test_create_project_with_metadata- 带元数据创建 - ✅
test_create_project_invalid_type- 无效类型 - ✅
test_create_project_duplicate_name- 重名项目
项目详情:
- ✅
test_get_project_success- 获取详情成功 - ✅
test_get_project_not_found- 项目不存在
更新项目:
- ✅
test_update_project_success- 更新成功 - ✅
test_update_project_partial- 部分更新
回收站:
- ✅
test_delete_project_to_trash- 移至回收站 - ✅
test_get_trash_projects- 获取回收站列表 - ✅
test_restore_project- 恢复项目 - ✅
test_permanent_delete- 永久删除
项目移动:
- ✅
test_move_project- 移动项目
项目克隆:
- ✅
test_clone_project- 克隆项目
项目导出:
- ✅
test_export_project- 导出项目
分享管理:
- ✅
test_create_share- 创建分享 - ✅
test_get_shares- 获取分享列表 - ✅
test_revoke_share- 撤销分享
成员管理:
- ✅
test_get_members- 获取成员列表 - ✅
test_add_member- 添加成员 - ✅
test_remove_member- 移除成员
项目顺序:
- ✅
test_update_project_order- 更新顺序
测试数据准备
Fixtures
测试使用以下 fixtures 准备测试数据:
@pytest.fixture
async def test_user(session: AsyncSession):
"""创建测试用户"""
# 创建并返回测试用户
@pytest.fixture
async def test_project(session: AsyncSession, test_user: User):
"""创建测试项目"""
# 创建并返回测试项目
@pytest.fixture
def auth_headers(test_user: User):
"""创建认证头"""
# 返回认证头字典
数据清理
测试使用事务回滚机制自动清理数据:
@pytest.fixture
async def session():
"""创建测试数据库会话"""
async with async_session_maker() as session:
async with session.begin():
yield session
await session.rollback() # 自动回滚
Mock 策略
服务层测试 Mock
服务层测试使用 Mock 隔离依赖:
# Mock repository 方法
project_service.repository.get_by_id = AsyncMock(return_value=sample_project)
project_service.repository.check_user_permission = AsyncMock(return_value=True)
API 测试不使用 Mock
API 集成测试使用真实的数据库连接,不使用 Mock:
# 使用真实的数据库会话
async with TestingSessionLocal() as session:
# 执行真实的数据库操作
测试最佳实践
1. 测试命名规范
# 格式:test_<功能>_<场景>
def test_create_project_success(): # ✅ 好
def test_create_project(): # ❌ 不够明确
2. 使用 AAA 模式
async def test_create_project_success():
# Arrange(准备)
project_data = ProjectCreate(name="测试项目", type="mine")
# Act(执行)
project = await service.create_project(user_id, project_data)
# Assert(断言)
assert project.name == "测试项目"
3. 测试独立性
每个测试应该独立运行,不依赖其他测试:
# ✅ 好:每个测试创建自己的数据
async def test_update_project():
project = await create_test_project()
# 测试逻辑
# ❌ 不好:依赖全局状态
global_project = None
async def test_create():
global global_project
global_project = await create_project()
4. 测试边界条件
# 测试正常情况
async def test_create_project_success():
pass
# 测试边界情况
async def test_create_project_empty_name():
pass
async def test_create_project_too_long_name():
pass
# 测试异常情况
async def test_create_project_duplicate_name():
pass
常见问题
1. 测试数据库连接失败
问题:测试无法连接到数据库
解决方案:
# 确保 Docker 容器正在运行
docker ps | grep jointo-server
# 检查数据库连接
docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "SELECT 1"
2. 测试数据未清理
问题:测试数据残留在数据库中
解决方案:
# 确保使用事务回滚
@pytest.fixture
async def session():
async with session.begin():
yield session
await session.rollback() # 添加回滚
3. Mock 未生效
问题:Mock 的方法没有被调用
解决方案:
# 确保 Mock 在正确的位置
# ❌ 错误
service.repository = Mock()
# ✅ 正确
service.repository.get_by_id = AsyncMock(return_value=project)
4. 异步测试超时
问题:异步测试运行超时
解决方案:
# 增加超时时间
@pytest.mark.asyncio
@pytest.mark.timeout(30) # 30 秒超时
async def test_long_running():
pass
持续集成
GitHub Actions 配置
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Start services
run: docker-compose up -d
- name: Run tests
run: docker exec jointo-server-app pytest --cov --cov-report=xml
- name: Upload coverage
uses: codecov/codecov-action@v2
测试覆盖率目标
| 层次 | 目标覆盖率 | 当前状态 |
|---|---|---|
| 仓储层 | > 90% | 待测试 |
| 服务层 | > 85% | 待测试 |
| API 层 | > 80% | 待测试 |
| 总体 | > 80% | 待测试 |
下一步计划
-
运行测试套件:
docker exec jointo-server-app pytest -v -
生成覆盖率报告:
docker exec jointo-server-app pytest --cov --cov-report=html -
修复失败的测试:
- 检查测试输出
- 修复代码或测试
- 重新运行测试
-
补充缺失的测试:
- 边界条件测试
- 异常情况测试
- 性能测试
文档创建时间:2026-01-29
最后更新:2026-01-29
维护者:Kiro AI Assistant