Files
invoice-master-poc-v2/tests/normalize/normalizers
2026-01-27 23:58:17 +01:00
..
2026-01-25 15:21:11 +01:00
2026-01-25 15:21:11 +01:00
2026-01-27 23:58:17 +01:00
2026-01-27 23:58:17 +01:00
2026-01-27 23:58:17 +01:00

Normalizer Tests

每个 normalizer 模块都有完整的测试覆盖。

测试结构

tests/normalize/normalizers/
├── __init__.py
├── test_invoice_number_normalizer.py    # InvoiceNumberNormalizer 测试 (12 个测试)
├── test_ocr_normalizer.py               # OCRNormalizer 测试 (9 个测试)
├── test_bankgiro_normalizer.py          # BankgiroNormalizer 测试 (11 个测试)
├── test_plusgiro_normalizer.py          # PlusgiroNormalizer 测试 (10 个测试)
├── test_amount_normalizer.py            # AmountNormalizer 测试 (15 个测试)
├── test_date_normalizer.py              # DateNormalizer 测试 (19 个测试)
├── test_organisation_number_normalizer.py  # OrganisationNumberNormalizer 测试 (11 个测试)
├── test_supplier_accounts_normalizer.py    # SupplierAccountsNormalizer 测试 (13 个测试)
├── test_customer_number_normalizer.py      # CustomerNumberNormalizer 测试 (12 个测试)
└── README.md                            # 本文件

运行测试

运行所有 normalizer 测试

# 在 WSL 环境中
conda activate invoice-py311
pytest tests/normalize/normalizers/ -v

运行单个 normalizer 的测试

# 测试 InvoiceNumberNormalizer
pytest tests/normalize/normalizers/test_invoice_number_normalizer.py -v

# 测试 AmountNormalizer
pytest tests/normalize/normalizers/test_amount_normalizer.py -v

# 测试 DateNormalizer
pytest tests/normalize/normalizers/test_date_normalizer.py -v

查看测试覆盖率

pytest tests/normalize/normalizers/ --cov=src/normalize/normalizers --cov-report=html

测试统计

总计: 112 个测试用例 状态: 全部通过 执行时间: ~5.6 秒

各 Normalizer 测试数量

Normalizer 测试数量 覆盖率
InvoiceNumberNormalizer 12 100%
OCRNormalizer 9 100%
BankgiroNormalizer 11 100%
PlusgiroNormalizer 10 100%
AmountNormalizer 15 100%
DateNormalizer 19 93%
OrganisationNumberNormalizer 11 100%
SupplierAccountsNormalizer 13 100%
CustomerNumberNormalizer 12 100%

测试覆盖的场景

通用测试 (所有 normalizer)

  • 空字符串处理
  • None 值处理
  • Callable 接口 (__call__)
  • 基本功能验证

InvoiceNumberNormalizer

  • 纯数字发票号
  • 带前缀的发票号 (INV-, etc.)
  • 字母数字混合
  • 特殊字符处理
  • Unicode 字符清理
  • 多个分隔符
  • 无数字内容
  • 重复变体去除

OCRNormalizer

  • 纯数字 OCR
  • 带前缀 (OCR:)
  • 空格分隔
  • 连字符分隔
  • 混合分隔符
  • 超长 OCR 号码

BankgiroNormalizer

  • 8 位数字 (带/不带连字符)
  • 7 位数字格式
  • 特殊连字符类型 (en-dash, etc.)
  • 空格处理
  • 前缀处理 (BG:)
  • OCR 错误变体生成

PlusgiroNormalizer

  • 8 位数字 (带/不带连字符)
  • 7 位数字
  • 9 位数字
  • 空格处理
  • 前缀处理 (PG:)
  • OCR 错误变体生成

AmountNormalizer

  • 整数金额
  • 逗号小数分隔符
  • 点小数分隔符
  • 空格千位分隔符
  • 空格作为小数分隔符 (瑞典格式)
  • 美国格式 (1,390.00)
  • 欧洲格式 (1.390,00)
  • 货币符号移除 (kr, SEK)
  • 大金额处理
  • 冒号破折号后缀 (1234:-)

DateNormalizer

  • ISO 格式 (2025-12-13)
  • 欧洲斜杠格式 (13/12/2025)
  • 欧洲点格式 (13.12.2025)
  • 紧凑格式 YYYYMMDD
  • 紧凑格式 YYMMDD
  • 短年份格式 (DD.MM.YY)
  • 瑞典月份名称 (december, dec)
  • 瑞典月份缩写
  • 带时间的 ISO 格式
  • 歧义日期双重解析
  • 中点分隔符
  • 空格格式
  • 无效日期处理
  • 2 位年份世纪判断

OrganisationNumberNormalizer

  • 带/不带连字符
  • VAT 号码提取
  • VAT 号码生成
  • 12 位带世纪组织号
  • VAT 带空格
  • 大小写混合 VAT 前缀
  • OCR 错误变体生成

SupplierAccountsNormalizer

  • 单个 Plusgiro
  • 单个 Bankgiro
  • 多账号 (| 分隔)
  • 前缀标准化
  • 前缀带空格
  • 空账号忽略
  • 无前缀账号
  • 7 位账号
  • 10 位账号
  • 混合格式账号

CustomerNumberNormalizer

  • 字母数字+空格+连字符
  • 字母数字+空格
  • 大小写变体
  • 纯数字
  • 仅连字符
  • 仅空格
  • 大写重复去除
  • 复杂客户编号
  • 瑞典客户编号格式 (UMJ 436-R)

最佳实践

1. 使用 pytest fixtures

每个测试类都使用 @pytest.fixture 创建 normalizer 实例:

@pytest.fixture
def normalizer(self):
    """Create normalizer instance for testing"""
    return InvoiceNumberNormalizer()

def test_something(self, normalizer):
    result = normalizer.normalize('test')
    assert 'expected' in result

2. 清晰的测试命名

测试方法名清楚描述测试场景:

def test_with_dash_8_digits(self, normalizer):
    """8-digit Bankgiro with dash should generate variants"""
    ...

3. 断言具体行为

明确测试期望的行为:

result = normalizer.normalize('5393-9484')
assert '5393-9484' in result  # 保留原始格式
assert '53939484' in result   # 生成无连字符格式

4. 边界条件测试

每个 normalizer 都测试:

  • 空字符串
  • None 值
  • 特殊字符
  • 极端值

5. 接口一致性测试

验证 callable 接口:

def test_callable_interface(self, normalizer):
    """Normalizer should be callable via __call__"""
    result = normalizer('test-value')
    assert result is not None

添加新测试

为新功能添加测试:

def test_new_feature(self, normalizer):
    """Description of what this tests"""
    # Arrange
    input_value = 'test-input'

    # Act
    result = normalizer.normalize(input_value)

    # Assert
    assert 'expected-output' in result
    assert len(result) > 0

CI/CD 集成

这些测试可以轻松集成到 CI/CD 流程:

# .github/workflows/test.yml
- name: Run Normalizer Tests
  run: pytest tests/normalize/normalizers/ -v --cov

总结

112 个测试全部通过 高覆盖率: 大部分 normalizer 达到 100% 快速执行: 5.6 秒完成所有测试 清晰结构: 每个 normalizer 独立测试文件 易维护: 遵循 pytest 最佳实践