- param_repository.resolve_values:窗口函数一条 SQL 取全量快照(同日多次变更取 effective_date DESC, id DESC 首条) - param_service.ParamSnapshot:冻结快照 + 覆盖链(角色 > 产品类别 > 默认行)+ 注册表默认值兜底;fraction/integer/boolean/text 类型化取值 - 12 项单元用例:覆盖链优先级、兜底、同日取最新、冻结不可变 Co-Authored-By: Claude Code <noreply@anthropic.com>
93 lines
3.8 KiB
Python
93 lines
3.8 KiB
Python
"""参数快照(时点化取值)测试。
|
||
|
||
守的是:覆盖链与兜底 —— 一旦取错维度(如企业户取到市政阈值行)
|
||
或漏兜底,核算会用错口径或直接崩溃;同日多次变更必须取最新留痕。
|
||
仓储 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) 的最新值在前。"""
|
||
return ParamSnapshot.from_rows(date(2026, 10, 1), 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]
|