"""质量门控测试(第三道防线).""" import json from src.ai.services.evaluation.llm_judge import JudgeResult, LLMJudge from src.ai.services.evaluation.quality_gate import QualityGate from src.ai.services.evaluation.rule_validator import RuleValidator from .conftest import MockProvider class TestQualityGate: """QualityGate 测试.""" async def test_rule_fail_rejects(self) -> None: """规则校验失败 → 拒绝.""" gate = QualityGate(rule_validator=RuleValidator()) result = await gate.evaluate(llm_output="invalid json") assert result.passed is False assert result.degraded is True assert result.score == 0.0 async def test_rule_pass_no_judge(self) -> None: """规则通过 + 无 LLM Judge → 放行.""" gate = QualityGate(rule_validator=RuleValidator(), llm_judge=None) output = json.dumps({"question": "完整的题目", "answer": "完整的答案"}) result = await gate.evaluate(output) assert result.passed is True assert result.score == 1.0 async def test_rule_pass_with_warnings_degraded(self) -> None: """规则通过但有 warning + 无 Judge → degraded.""" gate = QualityGate(rule_validator=RuleValidator(), llm_judge=None) output = json.dumps({"question": "ab", "answer": "答"}) result = await gate.evaluate(output) assert result.passed is True assert result.degraded is True async def test_with_llm_judge_pass(self) -> None: """规则 + LLM Judge 均通过.""" judge = LLMJudge(provider=MockProvider( response_content=json.dumps({ "overall": 0.9, "accuracy": 0.9, "clarity": 0.9, "correctness": 0.9, "completeness": 0.9, "difficulty_match": 0.9, "issues": [], }), )) gate = QualityGate(rule_validator=RuleValidator(), llm_judge=judge) output = json.dumps({"question": "完整题目", "answer": "完整答案"}) result = await gate.evaluate(output) assert result.passed is True assert result.judge_result is not None async def test_combine_scores(self) -> None: """综合评分权重 0.4 + 0.6.""" gate = QualityGate(rule_validator=RuleValidator()) combined = gate._combine_scores(1.0, 0.5) assert combined == 0.7 # 1.0*0.4 + 0.5*0.6 async def test_judge_unavailable_degrades(self) -> None: """LLM Judge 不可用 → 仅规则校验.""" judge = LLMJudge(provider=None) # provider=None gate = QualityGate(rule_validator=RuleValidator(), llm_judge=judge) output = json.dumps({"question": "完整题目", "answer": "完整答案"}) result = await gate.evaluate(output) assert result.judge_result is not None assert result.judge_result.available is False class TestLLMJudge: """LLMJudge 测试.""" async def test_no_provider_degrades(self) -> None: """无 provider → available=False.""" judge = LLMJudge(provider=None) result = await judge.judge("题", "答") assert result.available is False assert result.score == 0.7 async def test_provider_unavailable_degrades(self) -> None: """provider 未配置 → available=False.""" judge = LLMJudge(provider=MockProvider(available=False)) result = await judge.judge("题", "答") assert result.available is False async def test_parse_valid_response(self) -> None: """解析合法 JSON 评审响应.""" judge = LLMJudge(provider=MockProvider( response_content=json.dumps({ "overall": 0.85, "accuracy": 0.9, "clarity": 0.8, "correctness": 0.9, "completeness": 0.8, "difficulty_match": 0.85, "issues": ["解析不够详细"], }), )) result = await judge.judge("题", "答", difficulty="easy") assert result.available is True assert result.score == 0.85 assert result.issues == ["解析不够详细"] async def test_parse_invalid_json(self) -> None: """非法 JSON → available=False, score=0.5.""" judge = LLMJudge(provider=MockProvider(response_content="not json")) result = await judge.judge("题", "答") assert result.available is False assert result.score == 0.5 async def test_judge_result_passed(self) -> None: """JudgeResult.passed 属性.""" passed = JudgeResult(score=0.8, available=True) assert passed.passed is True failed = JudgeResult(score=0.3, available=True) assert failed.passed is False unavailable = JudgeResult(score=0.8, available=False) assert unavailable.passed is False async def test_parse_markdown_wrapped(self) -> None: """markdown 包裹的 JSON 能解析.""" judge = LLMJudge(provider=MockProvider( response_content='```json\n{"overall": 0.7}\n```', )) result = await judge.judge("题", "答") assert result.available is True assert result.score == 0.7