开发者测试指南
简介
本文档旨在指导开发者在 msModelSlim 项目中运行单元测试,帮助您了解测试环境配置及执行流程,确保能够顺利执行测试。
环境要求
按照《msModelSlim 安装指南 — 源码安装》章节完成编译和测试环境的搭建。
说明: 环境镜像的构建方法及配套软件版本由 MindStudio 统一镜像制作指南维护,本仓库不重复定义。
单元测试执行
执行如下命令执行单元测试,测试 modelslim_v1 相关模块(app、core、ir、infra、processor、utils):
cd ~/msmodelslim
python3 build.py test
输出典型测试
每个模块会显示测试进度和最终结果。输出格式示例如下:
Running modelslim_v1 related test cases...
===== test session starts =====
collected 57 items
cases/app/analysis/test_analysis_app.py ....... [ 26%]
cases/app/analysis/test_analysis_methods.py .................... [ 73%]
cases/app/naive_quantization/test_naive_quantization_app.py ...... [100%]
----- generated xml file: /path/to/report/final_app.xml -----
===== 57 passed, 6 warnings in 6.17s =====
===== test session starts =====
collected 406 items
cases/core/context/test_base_context.py ................. [ 4%]
...
----- generated xml file: /path/to/report/final_core.xml -----
===== 392 passed, 14 skipped, 4 warnings in 18.30s =====
Note
测试完成后会看到每个模块的统计信息,格式为 X passed, Y skipped, Z warnings。
单元测试编写
目录结构映射
测试用例的目录结构必须与源码目录结构保持一一对应。测试根目录为 test/cases/,其下按模块划分子目录,每个子目录对应 msmodelslim/ 下的同名模块。
映射规则:msmodelslim/<module>/<sub>/xxx.py → test/cases/<module>/<sub>/test_xxx.py
以 core 模块为例:
源码路径 测试用例路径
msmodelslim/core/ test/cases/core/
├── observer/ ├── observer/
│ ├── minmax.py ───────────────→ │ ├── test_minmax.py
│ └── histogram.py ───────────────→ │ └── test_histogram.py
├── quantizer/ ├── quantizer/
│ ├── base.py ───────────────→ │ ├── test_base.py
│ └── impl/ │ └── impl/
│ ├── minmax.py ───────────────→ │ ├── test_minmax.py
│ └── gptq.py ───────────────→ │ └── test_gptq.py
└── convert/ └── convert/
├── config.py ───────────────→ ├── test_config.py
└── router.py ───────────────→ └── test_router.py
新增测试用例
当需要为新增或已有源码文件补充测试时,按以下步骤操作:
-
定位目标目录:根据源码路径,找到
test/cases/下对应的目录。如果目录不存在,则创建。例如,新增源码文件
msmodelslim/core/quantizer/impl/new_quantizer.py,则应在test/cases/core/quantizer/impl/下创建测试文件。 -
创建测试文件:文件命名为
test_<源码模块名>.py,如test_new_quantizer.py。 -
编写测试内容:按照下文的规范编写测试类和测试方法。
命名规范
| 项目 | 规范 | 示例 |
|---|---|---|
| 测试文件 | test_<模块名>.py |
test_minmax.py、test_context_factory.py |
| 测试类 | Test<类名> |
TestW4A4Quantizer、TestMsMinMaxObserver |
| 测试方法 | test_<object>_<assertion>_when_<condition> |
test_quantize_raises_error_when_weight_out_of_range |
测试方法命名采用三段式结构:
| 段落 | 含义 | 示例 |
|---|---|---|
object |
被测试的方法或属性 | quantize、get_config、get_min_max |
assertion |
对结果的断言描述 | returns_none、raises_error、equals_expected |
condition |
触发该行为的前置条件 | input_is_empty、weight_out_of_range、not_updated |
Note
命名即文档。当测试失败时,方法名应能直接定位是哪个场景出了问题,而非仅仅"某个功能挂了"。例如 test_quantize_raises_error_when_weight_out_of_range 失败 → 边界处理有问题;test_quantize_works 失败 → 只知道"量化有问题"。
测试类与文件规范
- 源码中每个类必须对应一个测试类,测试类名以
Test为前缀(如W4A4Quantizer→TestW4A4Quantizer)。 - 测试类须添加 docstring,说明被测目标。
- 同一文件中可包含多个测试类,按被测类从上到下排列。
- 每个测试方法须添加中文 docstring,采用 场景/预期 格式:
"""场景:xxx。预期:yyy。"""。 - 每个测试文件必须包含标准版权声明头。
- 导入顺序:标准库 → 第三方库 → 项目内部模块,各组之间空一行;项目内部模块使用完整包路径导入。
测试范围与场景设计
测试范围
- 必须覆盖:所有公开方法和属性(外部接口)。
- 建议覆盖:包含非平凡逻辑的核心内部/私有方法。
场景化测试设计
一个测试用例 = 一个场景,而非一个功能一个用例。
对每个方法,应从以下三类场景设计测试:
| 场景类别 | 说明 | 示例 |
|---|---|---|
| Normal | 典型、合法的输入 | 合法 shape 的 tensor |
| Boundary | 边界条件、极限值 | 空 tensor、最小/最大值、单元素 |
| Exception | 应抛异常的非法输入 | None 输入、错误类型、超范围值 |
实现清单
为类编写测试时,按以下顺序执行:
- 映射类:列出所有公开方法和核心内部方法。
- 识别场景:对每个方法枚举 Normal / Boundary / Exception 场景。
- 命名用例:使用
test_<object>_<assertion>_when_<condition>格式。 - 编写测试:每个测试只聚焦一个场景。
- 验证覆盖:确保每个公开方法至少有一个 Normal 场景测试;有输入校验或范围约束的方法须补充 Boundary 和 Exception 场景。
conftest.py 使用
conftest.py 用于定义测试 fixtures 和通用 mock 配置,pytest 会自动发现并加载。
层级规则
test/cases/core/conftest.py:core 模块全局配置,所有 core 子目录的测试共享。test/cases/core/<sub>/conftest.py:子模块专属配置,仅该子目录下的测试可见。
当前 test/cases/core/conftest.py 已包含以下通用配置:
mock_init_config():初始化配置 mockmock_kia_library():KIA 库 mockmock_security_library():安全校验 mocksample_torch_tensorfixture:标准 float tensormock_dataset_loaderfixture:校准数据 loader mockmock_context_factoryfixture:上下文工厂 mock
新增 fixture 时,根据作用范围选择放置层级:
- 多个子模块共享 → 放在
test/cases/core/conftest.py - 仅单个子模块使用 → 放在
test/cases/core/<sub>/conftest.py
常用测试模式
| 模式 | 用法 | 关键 API |
|---|---|---|
| 异常断言 | 验证异常类型和消息 | pytest.raises(ExceptionType, match="...") |
| 浮点数比较 | 避免浮点精度问题 | assert val == pytest.approx(expected) |
| Mock 外部依赖 | 隔离外部依赖 | unittest.mock.Mock、patch、MagicMock |
| 抽象方法验证 | 验证抽象基类方法标记 | getattr(cls.method, "__isabstractmethod__", False) |