# 项目服务测试指南 > **创建日期**:2026-01-29 > **测试覆盖**:项目管理服务完整测试套件 --- ## 测试概述 项目服务测试套件包含三个层次的测试: 1. **单元测试**:测试仓储层和服务层的独立功能 2. **集成测试**:测试 API 层与数据库的集成 3. **端到端测试**:测试完整的用户场景(待实现) --- ## 测试文件结构 ``` server/tests/ ├── unit/ │ ├── test_project_repository.py # 仓储层单元测试 │ └── test_project_service.py # 服务层单元测试 ├── integration/ │ └── test_project_api.py # API 集成测试 └── conftest.py # 测试配置和 fixtures ``` --- ## 运行测试 ### 运行所有测试 ```bash # 在容器内运行 docker exec jointo-server-app pytest # 或使用 pytest 标记 docker exec jointo-server-app pytest -v ``` ### 运行特定测试文件 ```bash # 仓储层测试 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 ``` ### 运行特定测试类或方法 ```bash # 运行特定测试类 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 ``` ### 生成测试覆盖率报告 ```bash # 生成覆盖率报告 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 准备测试数据: ```python @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): """创建认证头""" # 返回认证头字典 ``` ### 数据清理 测试使用事务回滚机制自动清理数据: ```python @pytest.fixture async def session(): """创建测试数据库会话""" async with async_session_maker() as session: async with session.begin(): yield session await session.rollback() # 自动回滚 ``` --- ## Mock 策略 ### 服务层测试 Mock 服务层测试使用 Mock 隔离依赖: ```python # 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: ```python # 使用真实的数据库会话 async with TestingSessionLocal() as session: # 执行真实的数据库操作 ``` --- ## 测试最佳实践 ### 1. 测试命名规范 ```python # 格式:test_<功能>_<场景> def test_create_project_success(): # ✅ 好 def test_create_project(): # ❌ 不够明确 ``` ### 2. 使用 AAA 模式 ```python 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. 测试独立性 每个测试应该独立运行,不依赖其他测试: ```python # ✅ 好:每个测试创建自己的数据 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. 测试边界条件 ```python # 测试正常情况 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. 测试数据库连接失败 **问题**:测试无法连接到数据库 **解决方案**: ```bash # 确保 Docker 容器正在运行 docker ps | grep jointo-server # 检查数据库连接 docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "SELECT 1" ``` ### 2. 测试数据未清理 **问题**:测试数据残留在数据库中 **解决方案**: ```python # 确保使用事务回滚 @pytest.fixture async def session(): async with session.begin(): yield session await session.rollback() # 添加回滚 ``` ### 3. Mock 未生效 **问题**:Mock 的方法没有被调用 **解决方案**: ```python # 确保 Mock 在正确的位置 # ❌ 错误 service.repository = Mock() # ✅ 正确 service.repository.get_by_id = AsyncMock(return_value=project) ``` ### 4. 异步测试超时 **问题**:异步测试运行超时 **解决方案**: ```python # 增加超时时间 @pytest.mark.asyncio @pytest.mark.timeout(30) # 30 秒超时 async def test_long_running(): pass ``` --- ## 持续集成 ### GitHub Actions 配置 ```yaml 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% | 待测试 | --- ## 下一步计划 1. **运行测试套件**: ```bash docker exec jointo-server-app pytest -v ``` 2. **生成覆盖率报告**: ```bash docker exec jointo-server-app pytest --cov --cov-report=html ``` 3. **修复失败的测试**: - 检查测试输出 - 修复代码或测试 - 重新运行测试 4. **补充缺失的测试**: - 边界条件测试 - 异常情况测试 - 性能测试 --- **文档创建时间**:2026-01-29 **最后更新**:2026-01-29 **维护者**:Kiro AI Assistant