300 lines
7.9 KiB
Markdown
300 lines
7.9 KiB
Markdown
# Tests
|
|
|
|
完整的测试套件,遵循 pytest 最佳实践组织。
|
|
|
|
## 📁 测试目录结构
|
|
|
|
```
|
|
tests/
|
|
├── __init__.py
|
|
├── README.md # 本文件
|
|
│
|
|
├── data/ # 数据模块测试
|
|
│ ├── __init__.py
|
|
│ └── test_csv_loader.py # CSV 加载器测试
|
|
│
|
|
├── inference/ # 推理模块测试
|
|
│ ├── __init__.py
|
|
│ ├── test_field_extractor.py # 字段提取器测试
|
|
│ └── test_pipeline.py # 推理管道测试
|
|
│
|
|
├── matcher/ # 匹配模块测试
|
|
│ ├── __init__.py
|
|
│ └── test_field_matcher.py # 字段匹配器测试
|
|
│
|
|
├── normalize/ # 标准化模块测试
|
|
│ ├── __init__.py
|
|
│ ├── test_normalizer.py # FieldNormalizer 测试 (85 tests)
|
|
│ └── normalizers/ # 独立 normalizer 测试
|
|
│ ├── __init__.py
|
|
│ ├── test_invoice_number_normalizer.py # 12 tests
|
|
│ ├── test_ocr_normalizer.py # 9 tests
|
|
│ ├── test_bankgiro_normalizer.py # 11 tests
|
|
│ ├── test_plusgiro_normalizer.py # 10 tests
|
|
│ ├── test_amount_normalizer.py # 15 tests
|
|
│ ├── test_date_normalizer.py # 19 tests
|
|
│ ├── test_organisation_number_normalizer.py # 11 tests
|
|
│ ├── test_supplier_accounts_normalizer.py # 13 tests
|
|
│ ├── test_customer_number_normalizer.py # 12 tests
|
|
│ └── README.md # Normalizer 测试文档
|
|
│
|
|
├── ocr/ # OCR 模块测试
|
|
│ ├── __init__.py
|
|
│ └── test_machine_code_parser.py # 机器码解析器测试
|
|
│
|
|
├── pdf/ # PDF 模块测试
|
|
│ ├── __init__.py
|
|
│ ├── test_detector.py # PDF 类型检测器测试
|
|
│ └── test_extractor.py # PDF 提取器测试
|
|
│
|
|
├── utils/ # 工具模块测试
|
|
│ ├── __init__.py
|
|
│ ├── test_utils.py # 基础工具测试
|
|
│ └── test_advanced_utils.py # 高级工具测试
|
|
│
|
|
├── test_config.py # 配置测试
|
|
├── test_customer_number_parser.py # 客户编号解析器测试
|
|
├── test_db_security.py # 数据库安全测试
|
|
├── test_exceptions.py # 异常测试
|
|
└── test_payment_line_parser.py # 支付行解析器测试
|
|
```
|
|
|
|
## 📊 测试统计
|
|
|
|
**总测试数**: 628 个测试
|
|
**状态**: ✅ 全部通过
|
|
**执行时间**: ~7.7 秒
|
|
**代码覆盖率**: 37% (整体)
|
|
|
|
### 按模块分类
|
|
|
|
| 模块 | 测试文件数 | 测试数量 | 覆盖率 |
|
|
|------|-----------|---------|--------|
|
|
| **normalize** | 10 | 197 | ~98% |
|
|
| - normalizers/ | 9 | 112 | 100% |
|
|
| - test_normalizer.py | 1 | 85 | 71% |
|
|
| **utils** | 2 | ~149 | 73-93% |
|
|
| **pdf** | 2 | ~282 | 94-97% |
|
|
| **matcher** | 1 | ~402 | - |
|
|
| **ocr** | 1 | ~146 | 25% |
|
|
| **inference** | 2 | ~408 | - |
|
|
| **data** | 1 | ~282 | - |
|
|
| **其他** | 4 | ~110 | - |
|
|
|
|
## 🚀 运行测试
|
|
|
|
### 运行所有测试
|
|
|
|
```bash
|
|
# 在 WSL 环境中
|
|
conda activate invoice-py311
|
|
pytest tests/ -v
|
|
```
|
|
|
|
### 运行特定模块的测试
|
|
|
|
```bash
|
|
# Normalizer 测试
|
|
pytest tests/normalize/ -v
|
|
|
|
# 独立 normalizer 测试
|
|
pytest tests/normalize/normalizers/ -v
|
|
|
|
# PDF 测试
|
|
pytest tests/pdf/ -v
|
|
|
|
# Utils 测试
|
|
pytest tests/utils/ -v
|
|
|
|
# Inference 测试
|
|
pytest tests/inference/ -v
|
|
```
|
|
|
|
### 运行单个测试文件
|
|
|
|
```bash
|
|
pytest tests/normalize/normalizers/test_amount_normalizer.py -v
|
|
pytest tests/pdf/test_extractor.py -v
|
|
pytest tests/utils/test_utils.py -v
|
|
```
|
|
|
|
### 查看测试覆盖率
|
|
|
|
```bash
|
|
# 生成覆盖率报告
|
|
pytest tests/ --cov=src --cov-report=html
|
|
|
|
# 仅查看某个模块的覆盖率
|
|
pytest tests/normalize/ --cov=src/normalize --cov-report=term-missing
|
|
```
|
|
|
|
### 运行特定测试
|
|
|
|
```bash
|
|
# 按测试类运行
|
|
pytest tests/normalize/normalizers/test_amount_normalizer.py::TestAmountNormalizer -v
|
|
|
|
# 按测试方法运行
|
|
pytest tests/normalize/normalizers/test_amount_normalizer.py::TestAmountNormalizer::test_integer_amount -v
|
|
|
|
# 按关键字运行
|
|
pytest tests/ -k "normalizer" -v
|
|
pytest tests/ -k "amount" -v
|
|
```
|
|
|
|
## 🎯 测试最佳实践
|
|
|
|
### 1. 目录结构镜像源代码
|
|
|
|
测试目录结构镜像 `src/` 目录:
|
|
|
|
```
|
|
src/normalize/normalizers/amount_normalizer.py
|
|
tests/normalize/normalizers/test_amount_normalizer.py
|
|
```
|
|
|
|
### 2. 测试文件命名
|
|
|
|
- 测试文件以 `test_` 开头
|
|
- 测试类以 `Test` 开头
|
|
- 测试方法以 `test_` 开头
|
|
|
|
### 3. 使用 pytest fixtures
|
|
|
|
```python
|
|
@pytest.fixture
|
|
def normalizer():
|
|
"""Create normalizer instance for testing"""
|
|
return AmountNormalizer()
|
|
|
|
def test_something(normalizer):
|
|
result = normalizer.normalize('test')
|
|
assert 'expected' in result
|
|
```
|
|
|
|
### 4. 清晰的测试描述
|
|
|
|
```python
|
|
def test_with_comma_decimal(self, normalizer):
|
|
"""Amount with comma decimal should generate dot variant"""
|
|
result = normalizer.normalize('114,00')
|
|
assert '114.00' in result
|
|
```
|
|
|
|
### 5. Arrange-Act-Assert 模式
|
|
|
|
```python
|
|
def test_example(self):
|
|
# Arrange
|
|
input_data = 'test-input'
|
|
expected = 'expected-output'
|
|
|
|
# Act
|
|
result = process(input_data)
|
|
|
|
# Assert
|
|
assert expected in result
|
|
```
|
|
|
|
## 📝 添加新测试
|
|
|
|
### 为新功能添加测试
|
|
|
|
1. 在相应的 `tests/` 子目录创建测试文件
|
|
2. 遵循命名约定: `test_<module_name>.py`
|
|
3. 创建测试类和方法
|
|
4. 运行测试验证
|
|
|
|
示例:
|
|
|
|
```python
|
|
# tests/new_module/test_new_feature.py
|
|
import pytest
|
|
from src.new_module.new_feature import NewFeature
|
|
|
|
|
|
class TestNewFeature:
|
|
"""Test NewFeature functionality"""
|
|
|
|
@pytest.fixture
|
|
def feature(self):
|
|
"""Create feature instance for testing"""
|
|
return NewFeature()
|
|
|
|
def test_basic_functionality(self, feature):
|
|
"""Test basic functionality"""
|
|
result = feature.process('input')
|
|
assert result == 'expected'
|
|
|
|
def test_edge_case(self, feature):
|
|
"""Test edge case handling"""
|
|
result = feature.process('')
|
|
assert result == []
|
|
```
|
|
|
|
## 🔧 pytest 配置
|
|
|
|
项目的 pytest 配置在 `pyproject.toml`:
|
|
|
|
```toml
|
|
[tool.pytest.ini_options]
|
|
testpaths = ["tests"]
|
|
python_files = ["test_*.py"]
|
|
python_classes = ["Test*"]
|
|
python_functions = ["test_*"]
|
|
```
|
|
|
|
## 📈 持续集成
|
|
|
|
测试可以轻松集成到 CI/CD:
|
|
|
|
```yaml
|
|
# .github/workflows/test.yml
|
|
- name: Run Tests
|
|
run: |
|
|
conda activate invoice-py311
|
|
pytest tests/ -v --cov=src --cov-report=xml
|
|
|
|
- name: Upload Coverage
|
|
uses: codecov/codecov-action@v3
|
|
with:
|
|
file: ./coverage.xml
|
|
```
|
|
|
|
## 🎨 测试覆盖率目标
|
|
|
|
| 模块 | 当前覆盖率 | 目标 |
|
|
|------|-----------|------|
|
|
| normalize/ | 98% | ✅ 达标 |
|
|
| utils/ | 73-93% | 🎯 提升到 90% |
|
|
| pdf/ | 94-97% | ✅ 达标 |
|
|
| inference/ | 待评估 | 🎯 80% |
|
|
| matcher/ | 待评估 | 🎯 80% |
|
|
| ocr/ | 25% | 🎯 提升到 70% |
|
|
|
|
## 📚 相关文档
|
|
|
|
- [Normalizer Tests](normalize/normalizers/README.md) - 独立 normalizer 测试详细文档
|
|
- [pytest Documentation](https://docs.pytest.org/) - pytest 官方文档
|
|
- [Code Coverage](https://coverage.readthedocs.io/) - 覆盖率工具文档
|
|
|
|
## ✅ 测试检查清单
|
|
|
|
添加新功能时,确保:
|
|
|
|
- [ ] 创建对应的测试文件
|
|
- [ ] 测试正常功能
|
|
- [ ] 测试边界条件 (空值、None、空字符串)
|
|
- [ ] 测试错误处理
|
|
- [ ] 测试覆盖率 > 80%
|
|
- [ ] 所有测试通过
|
|
- [ ] 更新相关文档
|
|
|
|
## 🎉 总结
|
|
|
|
- ✅ **628 个测试**全部通过
|
|
- ✅ **镜像源代码**的清晰目录结构
|
|
- ✅ **遵循 pytest 最佳实践**
|
|
- ✅ **完整的文档**
|
|
- ✅ **易于维护和扩展**
|