PayrollManagementSystem/backend/tests/unit/test_param_snapshot.py

96 lines
4.0 KiB
Python
Raw Normal View History

"""参数快照(时点化取值)测试。
守的是:覆盖链与兜底 —— 一旦取错维度(如企业户取到市政阈值行)
或漏兜底,核算会用错口径或直接崩溃;同日多次变更必须取最新留痕。
仓储 SQL 的排序语义(同日取 id 最大)在集成测试中覆盖。
"""
from dataclasses import FrozenInstanceError
from datetime import date
from fractions import Fraction
import pytest
from app.services.param_service import ParamSnapshot
def _snap(rows: list[tuple[str, str, str]]) -> ParamSnapshot:
"""构造快照。rows 须模拟仓储输出:同一 (code, dim) 的最新值在前。"""
# 仓储实际返回 4 元组(含生效日期);单测关注覆盖链,统一补同一个日期
return ParamSnapshot.from_rows(
date(2026, 10, 1), [(code, dim, value, date(2026, 1, 1)) for code, dim, value in rows]
)
class TestCoverChain:
"""覆盖链:角色维度 > 产品类别维度 > 默认行('')。"""
def test_产品类别维度优先于默认行(self) -> None:
snap = _snap([("enterprise.rate", "", "3"), ("enterprise.rate", "municipal_water", "2")])
assert snap.get("enterprise.rate", product_category="municipal_water") == "2"
def test_无匹配维度时落默认行(self) -> None:
snap = _snap([("enterprise.rate", "", "3"), ("enterprise.rate", "municipal_water", "2")])
assert snap.get("enterprise.rate", product_category="rail_transit") == "3"
def test_角色维度优先于产品类别维度(self) -> None:
snap = _snap([("some.param", "municipal_water", "A"), ("some.param", "salesperson", "B")])
got = snap.get("some.param", role_code="salesperson", product_category="municipal_water")
assert got == "B"
def test_无任何维度匹配且无默认行_回退注册表默认值(self) -> None:
snap = _snap([("enterprise.rate", "municipal_water", "2")])
# 轨交无行、无默认行 → 回退注册表 default_value(3)
assert snap.fraction("enterprise.rate", product_category="rail_transit") == Fraction(3)
class TestFallback:
"""注册表默认值兜底(种子缺失时的安全网)。"""
def test_未定义参数按注册表默认值兜底(self) -> None:
snap = _snap([])
assert snap.fraction("prepay.rate") == Fraction(10)
def test_未注册编码抛ValueError_属代码缺陷(self) -> None:
snap = _snap([])
with pytest.raises(ValueError):
snap.fraction("not.registered.code")
class TestSameDayChanges:
"""同日多次变更:仓储 SQL 已按 (effective_date, id) 倒序,快照取先出现者。"""
def test_同日多次变更取最新一条(self) -> None:
snap = _snap([("enterprise.rate", "", "3"), ("enterprise.rate", "", "2")])
assert snap.fraction("enterprise.rate") == Fraction(3)
class TestTypedGetters:
"""类型化取值:Fraction 精确解析、整数、布尔、文本。"""
def test_fraction精确解析分数式(self) -> None:
snap = _snap([("salesperson.rate.slope", "salesperson", "4/360")])
assert snap.fraction("salesperson.rate.slope", role_code="salesperson") == Fraction(1, 90)
def test_integer(self) -> None:
snap = _snap([("salesperson.days.boundary", "salesperson", "360")])
assert snap.integer("salesperson.days.boundary", role_code="salesperson") == 360
def test_text返回枚举原文(self) -> None:
snap = _snap([("payment.weight.mode", "", "FULL")])
assert snap.text("payment.weight.mode") == "FULL"
def test_boolean(self) -> None:
snap = _snap([("some.flag", "", "1")])
assert snap.boolean("some.flag") is True
assert snap.boolean("some.flag") is not False
class TestImmutability:
"""快照冻结:解析结果不得被调用方改写(核算期间一致性)。"""
def test_字段不可赋值(self) -> None:
snap = _snap([])
with pytest.raises(FrozenInstanceError):
snap.biz_date = date(2026, 1, 1) # type: ignore[misc]