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

项目服务测试指南

创建日期: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

运行测试

运行所有测试

# 在容器内运行
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% 待测试

下一步计划

  1. 运行测试套件

    docker exec jointo-server-app pytest -v
    
  2. 生成覆盖率报告

    docker exec jointo-server-app pytest --cov --cov-report=html
    
  3. 修复失败的测试

    • 检查测试输出
    • 修复代码或测试
    • 重新运行测试
  4. 补充缺失的测试

    • 边界条件测试
    • 异常情况测试
    • 性能测试

文档创建时间:2026-01-29
最后更新:2026-01-29
维护者:Kiro AI Assistant