Some checks failed
Test / test (push) Failing after 3m47s
- 替换 Field(max_length=X) 为 StrX/TextX 类型别名(21 个 sqlmodels 文件) - 替换 get + 404 检查为 get_exist_one()(17 个路由文件,约 50 处) - 替换 save + session.refresh 为 save(load=...) - 替换 session.add + commit 为 save()(dav/provider.py) - 更新所有依赖至最新版本 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
DiskNext Server 单元测试文档
测试结构
tests/
├── conftest.py # Pytest 配置和 fixtures
├── unit/ # 单元测试
│ ├── models/ # 模型层测试
│ │ ├── test_base.py # TableBase/UUIDTableBase 测试
│ │ ├── test_user.py # User 模型测试
│ │ ├── test_group.py # Group/GroupOptions 测试
│ │ ├── test_object.py # Object 模型测试
│ │ └── test_setting.py # Setting 模型测试
│ ├── utils/ # 工具层测试
│ │ ├── test_password.py # Password 工具测试
│ │ └── test_jwt.py # JWT 工具测试
│ └── service/ # 服务层测试
│ └── test_login.py # Login 服务测试
└── README.md # 本文档
运行测试
安装依赖
# 使用 uv (推荐)
uv sync
# 或使用 pip
pip install -e .
运行所有测试
pytest
运行特定测试文件
# 测试模型层
pytest tests/unit/models/test_base.py
# 测试用户模型
pytest tests/unit/models/test_user.py
# 测试工具层
pytest tests/unit/utils/test_password.py
# 测试服务层
pytest tests/unit/service/test_login.py
运行特定测试函数
pytest tests/unit/models/test_base.py::test_table_base_add_single
运行带覆盖率的测试
# 生成覆盖率报告
pytest --cov
# 生成 HTML 覆盖率报告
pytest --cov --cov-report=html
# 查看 HTML 报告
# 打开 htmlcov/index.html
并行测试
# 使用所有 CPU 核心
pytest -n auto
# 使用指定数量的核心
pytest -n 4
Fixtures 说明
数据库相关
test_engine: 内存 SQLite 数据库引擎initialized_db: 已初始化表结构的数据库db_session: 数据库会话(每个测试函数独立)
用户相关(在 conftest.py 中已提供)
test_user: 创建测试用户,返回 {id, username, password, token, group_id, policy_id}admin_user: 创建管理员用户auth_headers: 测试用户的认证请求头admin_headers: 管理员的认证请求头
数据相关
test_directory: 为测试用户创建目录结构
测试覆盖范围
模型层 (tests/unit/models/)
test_base.py - TableBase/UUIDTableBase
- ✅ 单条记录创建
- ✅ 批量创建
- ✅ save() 方法
- ✅ update() 方法
- ✅ delete() 方法
- ✅ get() 三种 fetch_mode
- ✅ offset/limit 分页
- ✅ get_exist_one() 存在/不存在场景
- ✅ UUID 自动生成
- ✅ 时间戳自动维护
test_user.py - User 模型
- ✅ 创建用户
- ✅ 用户名唯一约束
- ✅ to_public() DTO 转换
- ✅ 用户与用户组关系
- ✅ status 默认值
- ✅ storage 默认值
- ✅ ThemeType 枚举
test_group.py - Group/GroupOptions 模型
- ✅ 创建用户组
- ✅ 用户组与选项一对一关系
- ✅ to_response() DTO 转换
- ✅ 多对多关系(policies)
test_object.py - Object 模型
- ✅ 创建目录
- ✅ 创建文件
- ✅ is_file 属性
- ✅ is_folder 属性
- ✅ get_root() 方法
- ✅ get_by_path() 根目录
- ✅ get_by_path() 嵌套路径
- ✅ get_by_path() 路径不存在
- ✅ get_children() 方法
- ✅ 父子关系
- ✅ 同目录名称唯一约束
test_setting.py - Setting 模型
- ✅ 创建设置
- ✅ type+name 唯一约束
- ✅ SettingsType 枚举
- ✅ 更新设置值
工具层 (tests/unit/utils/)
test_password.py - Password 工具
- ✅ 默认长度生成密码
- ✅ 自定义长度生成密码
- ✅ 密码哈希
- ✅ 正确密码验证
- ✅ 错误密码验证
- ✅ TOTP 密钥生成
- ✅ TOTP 验证正确
- ✅ TOTP 验证错误
test_jwt.py - JWT 工具
- ✅ 访问令牌创建
- ✅ 自定义过期时间
- ✅ 刷新令牌创建
- ✅ 令牌解码
- ✅ 令牌过期
- ✅ 无效签名
服务层 (tests/unit/service/)
test_login.py - Login 服务
- ✅ 正常登录
- ✅ 用户不存在
- ✅ 密码错误
- ✅ 用户被封禁
- ✅ 需要 2FA
- ✅ 2FA 错误
- ✅ 2FA 成功
常见问题
1. 数据库连接错误
所有测试使用内存 SQLite 数据库,不需要外部数据库服务。
2. 导入错误
确保从项目根目录运行测试:
cd c:\Users\Administrator\Documents\Code\Server
pytest
3. 异步测试错误
项目已配置 pytest-asyncio,使用 @pytest.mark.asyncio 装饰器即可。
4. Fixture 依赖错误
检查 conftest.py 中是否定义了所需的 fixture,确保使用正确的参数名。
编写新测试
模板
"""
模块名称的单元测试
"""
import pytest
from sqlmodel.ext.asyncio.session import AsyncSession
from models.xxx import YourModel
@pytest.mark.asyncio
async def test_your_feature(db_session: AsyncSession):
"""测试功能描述"""
# 准备数据
instance = YourModel(field="value")
instance = await instance.save(db_session)
# 执行操作
result = await YourModel.get(db_session, YourModel.id == instance.id)
# 断言验证
assert result is not None
assert result.field == "value"
持续集成
项目配置了覆盖率要求(80%),确保新代码有足够的测试覆盖。
# 检查覆盖率是否达标
pytest --cov --cov-fail-under=80