Files
于小丘 6c96c43bea
Some checks failed
Test / test (push) Failing after 3m47s
refactor: 统一 sqlmodel_ext 用法至官方推荐模式
- 替换 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>
2026-03-09 11:13:16 +08:00
..

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