"""DAMA数据治理规则检查(财务七规则)测试 — 2026-08-30 覆盖 data_quality.py 的 _run_governance_checks(governance-check 端点核心逻辑): 7条规则:unit_check/dup_alert/orphan_check/virtual_pollution/entity_check/kpi_completeness/reconciliation + 评分规则(error 扣 min(15,count*3),warning 扣 min(10,count*1),规则4 manual 附加扣) 验收活数据对照(生产环境实测):reconciliation=3、kpi_completeness=53、其余0。 """ import json from datetime import datetime import pytest from app.models import ( KPIDefinition, KPIValue, KPIAlert, CashPlan, BudgetPlan, ) from app.api.data_quality import _run_governance_checks def _mk_kpi(db, **kw): defaults = { "entity_id": 1, "kpi_code": "TEST_001", "kpi_name": "测试KPI", "status": "active", "target_value": 100.0, "target_yearly": 100.0, "formula": "x", "data_source": "test", "data_owner": "财务部", "unit": "元", "kpi_level": "operational", } defaults.update(kw) k = KPIDefinition(**defaults) db.add(k) db.commit() db.refresh(k) return k def _mk_plan(db, **kw): defaults = { "entity_id": 1, "plan_type": "receive", "amount": 10.0, "plan_date": datetime(2026, 8, 1), "source": "manual", "status": "pending", } defaults.update(kw) p = CashPlan(**defaults) db.add(p) db.commit() db.refresh(p) return p def _mk_alert(db, kpi_id, plan_id, **kw): defaults = { "kpi_id": kpi_id, "alert_type": "cash_plan", "status": "pending", "alert_message": "应收预警", "suggestion": json.dumps({"plan_id": plan_id}), } defaults.update(kw) a = KPIAlert(**defaults) db.add(a) db.commit() db.refresh(a) return a class TestGovernanceSevenRules: def test_clean_db_all_pass(self, db): """空库:7条规则全部通过,score=100""" r = _run_governance_checks(db, 0) assert r["total_rules"] == 7 assert r["score"] == 100 assert r["total_deduct"] == 0 assert len(r["passed"]) == 7 for item in r["issues"]: assert item["count"] == 0 def test_all_rules_hit(self, db): """构造数据触发全部7条规则""" # KPI-1: active + 有值 + 年度目标100 但预算月度合计200(勾稽差异100%) k1 = _mk_kpi(db, kpi_code="KPI_001", kpi_name="勾稽KPI", target_yearly=100.0) db.add(KPIValue(kpi_id=k1.id, entity_id=1, period="2026-06", actual_value=50.0)) for m in range(1, 13): db.add(BudgetPlan(kpi_id=k1.id, entity_id=1, period=f"2026-{m:02d}", budget_value=200.0 / 12, budget_year=2026, budget_month=m, version="v1.0", status="active")) db.commit() # KPI-2: active 无任何值(KPI完整性命中) _mk_kpi(db, kpi_code="KPI_002", kpi_name="无值KPI", target_yearly=10.0) # KPI-3: 值实体=2 ≠ 定义实体=1(实体归属命中) k3 = _mk_kpi(db, kpi_code="KPI_003", kpi_name="实体错乱KPI", target_yearly=10.0) db.add(KPIValue(kpi_id=k3.id, entity_id=2, period="2026-06", actual_value=5.0)) db.commit() # 单位校验:amount=50000 > 10000(单位错乱命中) _mk_plan(db, id=1, amount=50000.0) # 虚拟污染:source=test_import(error)+ source=manual(待人工确认) _mk_plan(db, id=2, amount=100.0, source="test_import") _mk_plan(db, id=3, amount=100.0, source="manual") # 孤儿预警:plan_id=999 不存在(孤儿命中) _mk_alert(db, k1.id, 999) # 重复预警:plan_id=5 两条 pending(重复命中) _mk_plan(db, id=5, amount=100.0) _mk_alert(db, k1.id, 5) _mk_alert(db, k1.id, 5) r = _run_governance_checks(db, 0) by_rule = {i["rule"]: i for i in r["issues"]} assert by_rule["unit_check"]["count"] == 1 assert by_rule["dup_alert"]["count"] == 1 assert by_rule["orphan_check"]["count"] == 1 assert by_rule["virtual_pollution"]["count"] == 1 assert by_rule["virtual_pollution"]["manual_count"] == 3 # plan#1/#3/#5 默认manual assert by_rule["entity_check"]["count"] == 1 assert by_rule["kpi_completeness"]["count"] == 1 assert by_rule["reconciliation"]["count"] == 1 # 评分:5条error × min(15,3)=3 → 15;2条warning × 1 → 2;manual附加 min(10,3)=3 → 总扣20 assert r["total_deduct"] == 20 assert r["score"] == 80 assert len(r["passed"]) == 0 def test_entity_scoped(self, db): """entity_id 限定:只检查该实体数据""" k1 = _mk_kpi(db, kpi_code="KPI_001", kpi_name="实体1KPI", entity_id=1, target_yearly=10.0) k2 = _mk_kpi(db, kpi_code="KPI_002", kpi_name="实体2KPI", entity_id=2, target_yearly=10.0) db.add(KPIValue(kpi_id=k2.id, entity_id=2, period="2026-06", actual_value=5.0)) db.commit() r1 = _run_governance_checks(db, 1) comp1 = {i["rule"]: i["count"] for i in r1["issues"]} assert comp1["kpi_completeness"] == 1 # 实体1下KPI_001无值 assert comp1["entity_check"] == 0 # 实体1下无实体错乱 r2 = _run_governance_checks(db, 2) comp2 = {i["rule"]: i["count"] for i in r2["issues"]} assert comp2["kpi_completeness"] == 0 # KPI_002有值 assert comp2["entity_check"] == 0 # 值实体=2与定义实体=2一致 assert comp2["reconciliation"] == 0 # 无预算行不参与勾稽