Files
Edu/services/ai/tests/test_rule_validator.py
2026-07-10 18:57:39 +08:00

127 lines
4.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.
"""规则校验器测试(第一道防线)."""
import json
from src.ai.services.evaluation.rule_validator import (
MAX_QUESTION_LENGTH,
RuleValidator,
ValidationResult,
)
class TestRuleValidator:
"""RuleValidator 测试."""
def setup_method(self) -> None:
self.validator = RuleValidator()
def test_valid_json_passes(self) -> None:
"""合法 JSON 通过."""
output = json.dumps({
"question": "什么是勾股定理?",
"answer": "a² + b² = c²",
"explanation": "直角三角形两直角边的平方和等于斜边的平方",
})
result = self.validator.validate(output)
assert result.passed is True
assert result.score == 1.0
assert result.parsed is not None
def test_invalid_json_fails(self) -> None:
"""非 JSON 失败."""
result = self.validator.validate("这不是 JSON")
assert result.passed is False
assert "不是有效的 JSON" in result.errors[0]
def test_markdown_wrapped_json(self) -> None:
"""markdown 代码块包裹的 JSON 能解析."""
output = '```json\n{"question": "", "answer": ""}\n```'
result = self.validator.validate(output)
assert result.passed is True
def test_missing_question_fails(self) -> None:
"""缺少 question 字段失败."""
output = json.dumps({"answer": ""})
result = self.validator.validate(output)
assert result.passed is False
assert any("question" in e for e in result.errors)
def test_missing_answer_fails(self) -> None:
"""缺少 answer 字段失败."""
output = json.dumps({"question": ""})
result = self.validator.validate(output)
assert result.passed is False
assert any("answer" in e for e in result.errors)
def test_short_question_warning(self) -> None:
"""过短 question 产生 warning."""
output = json.dumps({"question": "ab", "answer": ""})
result = self.validator.validate(output)
assert result.passed is True
assert any("过短" in w for w in result.warnings)
assert result.score == 0.8 # 有 warning
def test_difficulty_mismatch_warning(self) -> None:
"""难度不匹配产生 warning."""
output = json.dumps({
"question": "这是一道题目",
"answer": "这是答案",
"difficulty": "easy",
})
result = self.validator.validate(output, expected_difficulty="hard")
assert result.passed is True
assert any("difficulty 不匹配" in w for w in result.warnings)
def test_invalid_difficulty_warning(self) -> None:
"""无效难度值产生 warning."""
output = json.dumps({
"question": "这是一道题目",
"answer": "这是答案",
"difficulty": "impossible",
})
result = self.validator.validate(output, expected_difficulty="easy")
assert result.passed is True
assert any("无效" in w for w in result.warnings)
def test_question_type_mismatch_warning(self) -> None:
"""题型不匹配产生 warning."""
output = json.dumps({
"question": "这是一道题目",
"answer": "这是答案",
"question_type": "single_choice",
})
result = self.validator.validate(
output, expected_question_type="essay",
)
assert result.passed is True
assert any("question_type 不匹配" in w for w in result.warnings)
def test_json_array_fails(self) -> None:
"""JSON 数组(非 dict失败."""
result = self.validator.validate('[1, 2, 3]')
assert result.passed is False
def test_long_question_warning(self) -> None:
"""过长 question 产生 warning."""
output = json.dumps({
"question": "" * (MAX_QUESTION_LENGTH + 1),
"answer": "",
})
result = self.validator.validate(output)
assert result.passed is True
assert any("过长" in w for w in result.warnings)
def test_score_no_warnings(self) -> None:
"""无 warning 时 score=1.0."""
output = json.dumps({
"question": "这是一道完整的题目",
"answer": "这是完整的答案",
})
result = self.validator.validate(output)
assert result.score == 1.0
def test_validation_result_score_failed(self) -> None:
"""失败时 score=0.0."""
result = ValidationResult(passed=False, errors=["err"])
assert result.score == 0.0