Files
verify-promotion-metric-def…/tests/test_verify_rules.py
chenfuqiang 04026d0372
All checks were successful
技能自动化发布 / release (push) Successful in 7s
feat: 职称评审核验助手首版 v1.0.1(verify-promotion-metric-default)
2026-09-13 16:05:20 +08:00

157 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""职称硬指标核验内核金标准用例(离线、确定性)。"""
from __future__ import annotations
import unittest
from _support import IsolatedDataRoot
def _metrics(rank="副教授", **overrides) -> dict:
base = {
"teacherName": "张老师",
"department": "化材学院",
"applyRank": rank,
"presidingProvincial": 1,
"corePapers": 4,
"teachingHours": 180,
"currentTitleYears": 6,
}
base.update(overrides)
return base
class VerifyRuleTestBase(unittest.TestCase):
def setUp(self) -> None:
self._root = IsolatedDataRoot()
self._root.__enter__()
from db.connection import init_db
init_db()
def tearDown(self) -> None:
self._root.__exit__(None, None, None)
def _verify(self, metrics=None, rank="副教授"):
from service.verify_service import load_thresholds, verify_metrics
return verify_metrics(metrics if metrics is not None else _metrics(rank=rank), load_thresholds(rank))
class TestMatrixColors(VerifyRuleTestBase):
def test_all_safe(self) -> None:
result = self._verify(_metrics(presidingProvincial=2, corePapers=5, teachingHours=200, currentTitleYears=8))
self.assertEqual(result["verdict"], "安全")
colors = {m["metric_key"]: m["color"] for m in result["matrix"]}
self.assertTrue(all(c == "green" for c in colors.values()))
def test_red_hard_fail(self) -> None:
result = self._verify(_metrics(corePapers=1))
self.assertEqual(result["verdict"], "硬伤")
red = [m for m in result["matrix"] if m["color"] == "red"]
self.assertEqual(red[0]["metric_key"], "core_papers")
self.assertIn("依据", red[0]["advice"])
def test_yellow_border_below_10_percent(self) -> None:
result = self._verify(_metrics(presidingProvincial=1, corePapers=3, teachingHours=165, currentTitleYears=6))
self.assertEqual(result["verdict"], "边缘")
colors = {m["metric_key"]: m["color"] for m in result["matrix"]}
self.assertEqual(colors["teaching_hours"], "yellow") # 165/160 = 3.1% 余量
self.assertEqual(colors["core_papers"], "yellow") # 3/3 = 0 余量
def test_green_boundary_at_exactly_10_percent(self) -> None:
# 恰好 10% 余量(176 = 160×1.10)属绿
result = self._verify(_metrics(teachingHours=176))
colors = {m["metric_key"]: m["color"] for m in result["matrix"]}
self.assertEqual(colors["teaching_hours"], "green")
def test_r4_missing_metric_pending(self) -> None:
result = self._verify(_metrics(corePapers=None))
self.assertEqual(result["verdict"], "边缘")
colors = {m["metric_key"]: m["color"] for m in result["matrix"]}
self.assertEqual(colors["core_papers"], "gray")
pending = next(m for m in result["matrix"] if m["metric_key"] == "core_papers")
self.assertIn("R4", pending["advice"])
def test_v1_unconfigured_metric(self) -> None:
result = self._verify(_metrics(someExtraAward=3))
v1 = [m for m in result["matrix"] if m["metric_key"] == "someExtraAward"]
self.assertTrue(v1)
self.assertIn("V1", v1[0]["advice"])
class TestVerifyKernel(VerifyRuleTestBase):
def _run(self, cases):
from service.verify_service import run_verify
return run_verify(cases)
def test_run_verify_writes_reports_and_brief(self) -> None:
result = self._run([_metrics(presidingProvincial=2), _metrics(teacherName="李老师", corePapers=1)])
self.assertEqual(result["count"], 2)
self.assertEqual(result["verdict_counts"], {"安全": 1, "硬伤": 1})
self.assertTrue(result["brief_file"].endswith(".html"))
for report in result["reports"]:
self.assertTrue(report["report_file"].endswith(".html"))
with open(report["report_file"], encoding="utf-8") as f:
html_text = f.read()
self.assertIn("职称申报核验报告", html_text)
self.assertIn("不构成评审结论", html_text)
def test_empty_cases_raises(self) -> None:
with self.assertRaises(ValueError):
self._run([])
def test_professor_rank_thresholds(self) -> None:
result = self._run([_metrics(rank="教授", presidingProvincial=2, corePapers=7, monographs=2)])
self.assertEqual(result["reports"][0]["verdict"], "边缘") # core 7/6 余量 16.7% 绿、presiding 2/2 黄
def test_set_threshold_changes_verdict(self) -> None:
from service.threshold_service import upsert_threshold
upsert_threshold({"rank": "副教授", "metric_key": "core_papers", "metric_name": "核心期刊论文", "min_value": 5})
result = self._verify(_metrics(corePapers=4))
self.assertEqual(result["verdict"], "硬伤")
class TestThresholdService(VerifyRuleTestBase):
def test_upsert_threshold_create_update(self) -> None:
from service.threshold_service import list_thresholds, upsert_threshold
payload = upsert_threshold({"rank": "副教授", "metric_key": "awards", "metric_name": "教学/科研获奖", "min_value": 1})
self.assertEqual(payload["action"], "created")
payload = upsert_threshold({"rank": "副教授", "metric_key": "awards", "min_value": 2})
self.assertEqual(payload["action"], "updated")
rows = [t for t in list_thresholds("副教授") if t["metric_key"] == "awards"]
self.assertEqual(rows[0]["min_value"], 2.0)
def test_upsert_threshold_validations(self) -> None:
from service.threshold_service import upsert_threshold
with self.assertRaises(ValueError):
upsert_threshold({"rank": "院士", "metric_key": "awards", "min_value": 1})
with self.assertRaises(ValueError):
upsert_threshold({"rank": "副教授", "metric_key": "", "min_value": 1})
with self.assertRaises(ValueError):
upsert_threshold({"rank": "副教授", "metric_key": "awards", "min_value": -1})
def test_seeded_thresholds(self) -> None:
from service.threshold_service import list_thresholds
self.assertGreaterEqual(len(list_thresholds("副教授")), 4)
self.assertGreaterEqual(len(list_thresholds("教授")), 4)
def test_stats(self) -> None:
from service.threshold_service import stats
from service.verify_service import run_verify
run_verify([_metrics(presidingProvincial=2), _metrics(teacherName="李老师", corePapers=1)])
payload = stats()
self.assertEqual(payload["case_total"], 2)
self.assertEqual(payload["by_verdict"].get("硬伤"), 1)
self.assertTrue(payload["red_cases"])
if __name__ == "__main__":
unittest.main()