106 lines
3.7 KiB
Python
106 lines
3.7 KiB
Python
"""tests/unit/test_validate.py — 块验证纯决策函数的单元测试。"""
|
|
|
|
import pytest
|
|
|
|
from core.evolution.validate import classify_quadrants, compute_accuracy, pair_block
|
|
|
|
|
|
class TestPairBlock:
|
|
"""pair_block 逐题比对基线与候选的翻转统计测试。"""
|
|
|
|
def test_basic_flips(self) -> None:
|
|
"""基本翻转:一题从错到对(w)、一题从对到错(l)、一题不变。"""
|
|
baseline = {"q1": False, "q2": True, "q3": True}
|
|
candidate = {"q1": True, "q2": False, "q3": True}
|
|
result = pair_block(baseline, candidate, ["q1", "q2", "q3"])
|
|
assert result.w == 1
|
|
assert result.l == 1
|
|
assert result.observed == {
|
|
"q1": (False, True),
|
|
"q2": (True, False),
|
|
"q3": (True, True),
|
|
}
|
|
|
|
def test_empty(self) -> None:
|
|
"""空输入应返回零翻转。"""
|
|
result = pair_block({}, {}, [])
|
|
assert result.w == 0 and result.l == 0
|
|
|
|
def test_all_wins(self) -> None:
|
|
"""全部从错到对的极端情况。"""
|
|
baseline = {"q1": False, "q2": False}
|
|
candidate = {"q1": True, "q2": True}
|
|
result = pair_block(baseline, candidate, ["q1", "q2"])
|
|
assert result.w == 2
|
|
assert result.l == 0
|
|
|
|
def test_all_losses(self) -> None:
|
|
"""全部从对到错的极端情况。"""
|
|
baseline = {"q1": True, "q2": True}
|
|
candidate = {"q1": False, "q2": False}
|
|
result = pair_block(baseline, candidate, ["q1", "q2"])
|
|
assert result.w == 0
|
|
assert result.l == 2
|
|
|
|
def test_subset_of_questions(self) -> None:
|
|
"""只对 question_ids 中指定的子集进行比对。"""
|
|
baseline = {"q1": False, "q2": True, "q3": True}
|
|
candidate = {"q1": True, "q2": False, "q3": True}
|
|
result = pair_block(baseline, candidate, ["q1"])
|
|
assert result.w == 1
|
|
assert result.l == 0
|
|
assert "q2" not in result.observed
|
|
|
|
|
|
class TestClassifyQuadrants:
|
|
"""classify_quadrants 四象限分类测试。"""
|
|
|
|
def test_all_four(self) -> None:
|
|
"""四个象限各有一题。"""
|
|
observed = {
|
|
"q1": (False, True),
|
|
"q2": (True, False),
|
|
"q3": (False, False),
|
|
"q4": (True, True),
|
|
}
|
|
qc = classify_quadrants(observed)
|
|
assert qc.improvements == ["q1"]
|
|
assert qc.regressions == ["q2"]
|
|
assert qc.persistent_fails == ["q3"]
|
|
assert qc.stable_successes == ["q4"]
|
|
|
|
def test_sorted_within_quadrant(self) -> None:
|
|
"""同象限内题目 ID 应按字典序排列。"""
|
|
observed = {"z": (False, True), "a": (False, True)}
|
|
qc = classify_quadrants(observed)
|
|
assert qc.improvements == ["a", "z"]
|
|
|
|
def test_empty_observed(self) -> None:
|
|
"""空输入应返回全空象限。"""
|
|
qc = classify_quadrants({})
|
|
assert qc.improvements == []
|
|
assert qc.regressions == []
|
|
assert qc.persistent_fails == []
|
|
assert qc.stable_successes == []
|
|
|
|
|
|
class TestComputeAccuracy:
|
|
"""compute_accuracy 准确率计算测试。"""
|
|
|
|
def test_basic(self) -> None:
|
|
"""一对一错,准确率 0.5。"""
|
|
assert compute_accuracy({"q1": True, "q2": False}, ["q1", "q2"]) == 0.5
|
|
|
|
def test_all_correct(self) -> None:
|
|
"""全部正确,准确率 1.0。"""
|
|
assert compute_accuracy({"q1": True, "q2": True}, ["q1", "q2"]) == 1.0
|
|
|
|
def test_all_wrong(self) -> None:
|
|
"""全部错误,准确率 0.0。"""
|
|
assert compute_accuracy({"q1": False, "q2": False}, ["q1", "q2"]) == 0.0
|
|
|
|
def test_empty_raises(self) -> None:
|
|
"""空题目列表应抛出 ZeroDivisionError。"""
|
|
with pytest.raises(ZeroDivisionError):
|
|
compute_accuracy({}, [])
|