Markdown to DOCX 转换工具 - 测试规范
1. 测试概述
测试目标
- 确保功能正确性: 验证所有Markdown转换功能按预期工作
- 防止回归: 避免新功能破坏现有功能
- 提高代码质量: 通过测试驱动的开发方式
- 文档化行为: 测试用例作为功能使用示例
测试策略
- 单元测试: 测试单个组件的功能
- 集成测试: 测试组件间的协作
- 端到端测试: 测试完整转换流程
- 回归测试: 确保现有功能不受影响
2. 测试结构
目录结构
tests/
├── conftest.py # 测试配置和fixtures
├── unit/ # 单元测试
│ └── test_elements/ # 元素转换器测试
│ ├── test_heading.py # 标题转换测试
│ ├── test_text.py # 文本样式测试
│ ├── test_list.py # 列表转换测试
│ └── ... # 其他元素测试
├── integration/ # 集成测试
│ ├── test_full_conversion.py # 完整转换测试
│ ├── test_table_integration.py # 表格集成测试
│ └── ... # 其他集成测试
├── test.md # 综合回归样例
└── samples/ # 测试样例数据
├── basic/ # 基础语法样例(test_convert_all_samples)
│ ├── headings.md # 标题样例
│ ├── text_styles.md # 文本样式样例
│ ├── 1.png # image.md / tables.md 本地图资源
│ └── ... # 其他基础样例
├── advanced/ # 高级语法样例(test_convert_advanced_samples)
│ ├── tables.md # 表格样例
│ ├── math.md # 数学公式样例(含 \\label/\\ref)
│ ├── flowcharts.md # Mermaid 流程图(含 flowchart 关键字)
│ └── ... # 其他高级样例
└── large/ # 大文档样例(显式 chunked 冒烟)
└── chunked.mdconftest 样例 fixtures
| Fixture | 路径 |
|---|---|
samples_dir / samples_basic | tests/samples/basic/ |
samples_advanced | tests/samples/advanced/ |
samples_root | tests/samples/(含 test.md) |
测试文件命名规范
- 单元测试:
test_*.py - 测试方法:
test_*() - fixtures:
*_fixture或在conftest.py中定义
3. 单元测试规范
测试类结构
python
import pytest
from mddocx.converter.elements.heading import HeadingConverter
class TestHeadingConverter:
"""标题转换器测试类"""
@pytest.fixture
def converter(self):
"""创建转换器实例"""
return HeadingConverter()
def test_h1_conversion(self, converter):
"""测试H1标题转换"""
# 测试逻辑
pass
def test_h6_conversion(self, converter):
"""测试H6标题转换"""
# 测试逻辑
pass
def test_heading_with_styles(self, converter):
"""测试带样式的标题"""
# 测试逻辑
pass测试原则
- 独立性: 每个测试独立运行,不依赖其他测试
- 可重复性: 多次运行结果一致
- 快速执行: 单个测试在秒级完成
- 明确断言: 清晰的成功/失败标准
断言规范
python
# 正确示例
assert result is not None
assert len(paragraphs) == 3
assert paragraph.text == "期望文本"
# 避免模糊断言
# assert result # 太模糊
# assert True # 无意义4. 集成测试规范
端到端测试
python
def test_full_markdown_conversion():
"""测试完整Markdown文档转换"""
# 测试数据
markdown_content = """
# 主标题
这是一个**粗体**和*斜体*文本。
## 二级标题
- 项目1
- 项目2
- 子项目
```python
print("Hello, World!")
```
| 表头1 | 表头2 |
|-------|-------|
| 数据1 | 数据2 |
"""
from mddocx.converter.base import BaseConverter
converter = BaseConverter()
doc = converter.convert(markdown_content)
# 验证结果
assert doc is not None
# 验证标题
headings = [p for p in doc.paragraphs if p.style.name.startswith('Heading')]
assert len(headings) == 2
# 验证列表
# ... 更多验证逻辑组件集成测试
python
def test_table_with_list_integration():
"""测试表格和列表的集成转换"""
content = """
| 功能 | 状态 |
|------|------|
| 标题 | ✅ |
| 列表 | ✅ |
- 功能列表
- 子功能1
- 子功能2
"""
from mddocx.converter.base import BaseConverter
converter = BaseConverter()
doc = converter.convert(content)
# 验证表格存在
tables = doc.tables
assert len(tables) == 1
# 验证列表存在
# ... 验证逻辑5. 测试数据管理
可选依赖 html-for-docx
Markdown 内嵌的复杂 HTML 块在自研解析无法处理时,回退依赖 html-for-docx(pyproject.toml → [project.optional-dependencies] html;import 名为 html4docx):
bash
pip install -e ".[html]" # 或 pip install mddocx[html]
pytest tests/unit/test_elements/test_html.py tests/integration/test_html_integration.pyCI 默认不安装 [html];相关用例以 @pytest.mark.skipif(not HTML_FOR_DOCX_AVAILABLE) 跳过,属预期行为。代码中 HTML2DOCX_AVAILABLE 为兼容别名,与 HTML_FOR_DOCX_AVAILABLE 同值。
样例文件规范
- 文件位置:
tests/samples/basic/或tests/samples/advanced/ - 命名规范:
功能名称.md(如headings.md,tables.md) - 内容规范: 包含该功能的各种边界情况
- 注释说明: 在文件中添加注释说明特殊情况
示例样例文件
markdown
<!-- tests/samples/basic/headings.md -->
# H1 标题
## H2 标题
### H3 标题
#### H4 标题
##### H5 标题
###### H6 标题
# 带*样式*的标题
## 带**粗体**的标题
### 带[链接](url)的标题6. 测试运行和报告
基本运行命令
bash
# 运行所有测试(含 WebUI)
pytest tests/ src/mddocx/webui/tests/
# 运行单元测试
pytest tests/unit/
# 运行集成测试
pytest tests/integration/
# 运行 WebUI 测试
pytest src/mddocx/webui/tests/
# 运行特定测试文件
pytest tests/unit/test_elements/test_heading.py
# 运行特定测试方法
pytest tests/unit/test_elements/test_heading.py::TestHeadingConverter::test_h1_conversion测试配置
ini
# pyproject.toml 中的pytest配置
[tool.pytest.ini_options]
testpaths = ["tests", "src/mddocx/webui/tests"]
python_files = ["test_*.py"]
addopts = "-v"
pythonpath = ["src"]
markers = [
"slow: 运行较慢的测试",
"integration: 集成测试",
"unit: 单元测试"
]覆盖率报告
bash
# 生成HTML覆盖率报告
pytest --cov=src --cov-report=html
# 生成终端覆盖率报告
pytest --cov=src --cov-report=term
# 生成XML报告(用于CI)
pytest --cov=src --cov-report=xml7. 测试质量标准
覆盖率要求
- 语句覆盖率: ≥ 85%(当前基线 85%,v0.5.32 达标)
- 全量回归:
pytest tests/ src/mddocx/webui/tests/→ 259 passed(v0.5.42 基线 · T-TEST-03) - CI 报告:
pytest --cov=src/mddocx --cov-report=term-missing - WebUI 与
tests/samplesbasic/advanced 均已纳入 CI
性能标准
- 单元测试: 单个测试 < 0.1秒
- 集成测试: 单个测试 < 1秒
- 全量测试: 总运行时间 < 30秒
稳定性要求
- 测试通过率: 100% (除跳过测试外)
- 随机失败: < 1% (允许的随机失败率)
8. CI/CD集成
GitHub Actions配置
yaml
# .github/workflows/test.yml
name: Tests
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.8'
- name: Install dependencies
run: pip install -e .[dev]
- name: Run tests with coverage
run: pytest tests/ src/mddocx/webui/tests/ --cov=src --cov-report=xml
- name: Upload coverage reports
uses: codecov/codecov-action@v39. 测试维护
测试重构
当代码重构时,需要相应更新测试:
- 接口变更: 更新测试中的调用方式
- 行为变更: 修改测试断言
- 新增功能: 添加新的测试用例
测试债务管理
python
@pytest.mark.skip(reason="需要重构后实现")
def test_future_feature():
"""将来要实现的功能测试"""
pass性能回归检测
python
def test_conversion_performance(benchmark):
"""性能回归测试"""
markdown_content = generate_large_markdown()
# 基准测试
result = benchmark(convert_markdown, markdown_content)
# 性能断言
assert result.stats.mean < 1.0 # 平均转换时间 < 1秒10. 调试和故障排除
调试测试失败
bash
# 显示详细错误信息
pytest -v --tb=long
# 进入调试模式
pytest --pdb
# 只运行失败的测试
pytest --lf
# 显示print输出
pytest -s常见问题解决
- 路径问题: 使用
pathlib.Path和相对路径 - 编码问题: 统一使用UTF-8编码
- 依赖问题: 在
conftest.py中正确设置fixtures - 并发问题: 避免测试间的状态共享
此测试规范确保项目质量和可维护性。请所有开发者遵循此规范编写和维护测试。