"""评价权重计算引擎测试。""" import pytest from app.services.evaluation_engine import ( BASE_WEIGHTS, DIMENSION_KEY_MAP, calculate_weighted_score, compute_weights, get_dimension_score_key, ) class TestComputeWeights: """权重计算引擎测试。""" def test_basic_computation(self): """基本权重计算应返回有效结果。""" result = compute_weights( fund_type="early_vc", fund_lifecycle="investment", company_stage="a", industry="ai", strategy="growth", ) assert "weights" in result assert "enabled_dimensions" in result assert "disabled_dimensions" in result assert "custom_metrics" in result def test_weights_sum_to_100(self): """归一化后权重总和应等于 100。""" result = compute_weights( fund_type="early_vc", fund_lifecycle="growth", company_stage="b", industry="saas", strategy="value", ) total = sum(result["weights"].values()) assert abs(total - 100.0) < 0.5, f"权重总和应为 100,实际为 {total}" def test_disabled_dimensions_have_zero_weight(self): """禁用的维度不应出现在权重中。""" result = compute_weights( fund_type="pe", fund_lifecycle="investment", company_stage="c", industry="hardware", strategy="value", ) for dim in result["disabled_dimensions"]: assert dim not in result["weights"] or result["weights"][dim] == 0 def test_ai_industry_enables_all_dimensions(self): """AI 赛道应启用全部 14 维度。""" result = compute_weights( fund_type="early_vc", fund_lifecycle="investment", company_stage="a", industry="ai", ) assert len(result["enabled_dimensions"]) == 14 assert len(result["disabled_dimensions"]) == 0 def test_hardware_disables_ai_dimensions(self): """硬科技赛道应禁用 AI 相关维度。""" result = compute_weights( fund_type="early_vc", fund_lifecycle="investment", company_stage="a", industry="hardware", ) assert "ai_commercial" in result["disabled_dimensions"] assert "ai_cost" in result["disabled_dimensions"] assert "ai_model_product" in result["disabled_dimensions"] def test_biotech_disables_market_and_customer(self): """生物医药赛道应禁用市场竞争和客户成功。""" result = compute_weights( fund_type="angel", fund_lifecycle="investment", company_stage="seed", industry="biotech", ) assert "market_compete" in result["disabled_dimensions"] assert "customer_success" in result["disabled_dimensions"] def test_seed_stage_emphasizes_product_and_team(self): """种子期应提高产品技术和组织人才权重。""" result = compute_weights( fund_type="angel", fund_lifecycle="investment", company_stage="seed", industry="ai", ) weights = result["weights"] # 产品技术权重应高于财务 assert weights.get("product_tech", 0) > weights.get("financial", 0) # 组织人才权重应高于治理 assert weights.get("org_talent", 0) > weights.get("governance", 0) def test_pre_ipo_stage_emphasizes_financial_and_governance(self): """Pre-IPO 阶段应提高财务和治理权重。""" result = compute_weights( fund_type="growth_vc", fund_lifecycle="exit_preparation", company_stage="pre_ipo", industry="ai", ) weights = result["weights"] # 财务权重应高于产品技术 assert weights.get("financial", 0) > weights.get("product_tech", 0) # Pre-IPO 的治理权重应高于种子期 seed_result = compute_weights( fund_type="growth_vc", fund_lifecycle="exit_preparation", company_stage="seed", industry="ai", ) assert weights.get("governance", 0) > seed_result["weights"].get("governance", 0) def test_pe_fund_type_emphasizes_financial(self): """PE 基金应大幅提高财务权重。""" result = compute_weights( fund_type="pe", fund_lifecycle="growth", company_stage="b", industry="saas", ) weights = result["weights"] # PE 的财务权重应高于早期 VC vc_result = compute_weights( fund_type="early_vc", fund_lifecycle="investment", company_stage="b", industry="saas", ) assert weights.get("financial", 0) > vc_result["weights"].get("financial", 0) def test_custom_metrics_present(self): """各赛道应有专属指标。""" for industry in ["ai", "saas", "hardware", "biotech", "consumer", "fintech"]: result = compute_weights( fund_type="early_vc", fund_lifecycle="investment", company_stage="a", industry=industry, ) assert len(result["custom_metrics"]) >= 3, f"{industry} 赛道专属指标不足" def test_strategy_adjustment_effect(self): """投资策略微调应影响权重。""" base = compute_weights( fund_type="early_vc", fund_lifecycle="growth", company_stage="b", industry="ai", strategy="growth", ) value = compute_weights( fund_type="early_vc", fund_lifecycle="growth", company_stage="b", industry="ai", strategy="value", ) # 成长型策略市场权重应高于价值型 assert base["weights"].get("market_compete", 0) > value["weights"].get("market_compete", 0) # 价值型策略财务权重应高于成长型 assert value["weights"].get("financial", 0) > base["weights"].get("financial", 0) def test_all_weights_non_negative(self): """所有权重应为非负数。""" for fund_type in ["angel", "early_vc", "growth_vc", "pe", "cvc", "distress", "esg"]: for lifecycle in ["investment", "growth", "exit_preparation", "liquidation"]: for stage in ["seed", "a", "b", "c", "pre_ipo"]: for industry in ["ai", "saas", "hardware", "biotech", "consumer", "fintech"]: result = compute_weights( fund_type=fund_type, fund_lifecycle=lifecycle, company_stage=stage, industry=industry, ) for dim, weight in result["weights"].items(): assert weight >= 0, f"{fund_type}/{lifecycle}/{stage}/{industry} 的 {dim} 权重为负: {weight}" class TestCalculateWeightedScore: """加权评分计算测试。""" def test_basic_weighted_score(self): """基本加权评分计算。""" scores = {"financial": 80, "operational": 70, "product_tech": 90} weights = {"financial": 30, "operational": 30, "product_tech": 40} result = calculate_weighted_score(scores, weights) expected = (80 * 30 + 70 * 30 + 90 * 40) / 100 assert abs(result - expected) < 0.1 def test_missing_dimension_ignored(self): """缺失维度的评分应被忽略。""" scores = {"financial": 80} weights = {"financial": 50, "operational": 50} result = calculate_weighted_score(scores, weights) assert abs(result - 80.0) < 0.1 def test_empty_scores(self): """空评分应返回 0。""" result = calculate_weighted_score({}, {"financial": 100}) assert result == 0.0 class TestDimensionKeyMap: """维度 key 映射测试。""" def test_key_mapping(self): """权重 key 应正确映射到评分字段 key。""" assert get_dimension_score_key("financial") == "financial_score" assert get_dimension_score_key("ai_commercial") == "ai_commercial_score" assert get_dimension_score_key("customer_success") == "customer_success_score" def test_all_dimensions_mapped(self): """所有 14 维度都应有映射。""" assert len(DIMENSION_KEY_MAP) == 14 for key in BASE_WEIGHTS: assert key in DIMENSION_KEY_MAP, f"维度 {key} 缺少映射"