"""T2.1 企业详情聚合接口测试 + T2.9/T3.11 健康度维度扩展测试。 覆盖: - GET /companies/{id}/detail 聚合接口 - 14 维度健康度评分计算 - 趋势判断 """ import pytest from fastapi.testclient import TestClient from app.services.health_calculator import ( calculate_health_score, determine_trend, _calc_financial_score, _calc_operational_score, _calc_org_talent_score, _calc_product_tech_score, _calc_market_compete_score, _calc_governance_score, _calc_financing_score, _calc_synergy_score, _calc_ai_model_product_score, _calc_data_compliance_score, _calc_team_tech_score, _calc_customer_success_score, ) class TestCompanyDetailEndpoint: """T2.1 企业详情聚合接口测试。""" def test_get_company_detail_success(self, client: TestClient, auth_headers: dict, company_id: str): """测试获取企业详情聚合数据。""" resp = client.get(f"/api/v1/companies/{company_id}/detail", headers=auth_headers) assert resp.status_code == 200 data = resp.json()["data"] assert "company" in data assert data["company"]["id"] == company_id assert "recent_reports" in data assert "open_risks" in data assert "recent_weak_signals" in data assert "active_agreements" in data assert "recent_board_meetings" in data assert "financial_data_count" in data def test_get_company_detail_not_found(self, client: TestClient, auth_headers: dict): """测试获取不存在的企业详情。""" resp = client.get("/api/v1/companies/nonexistent-id/detail", headers=auth_headers) assert resp.status_code == 404 def test_get_company_detail_no_auth(self, client: TestClient, company_id: str): """测试未认证请求。""" resp = client.get(f"/api/v1/companies/{company_id}/detail") assert resp.status_code == 401 class TestHealthCalculator14Dimensions: """T2.9 + T3.11 健康度 14 维度评分测试。""" def test_empty_data_returns_zeros(self): """空数据应返回全 0。""" result = calculate_health_score({}) assert result["total_score"] == 0.0 assert result["financial_score"] == 0.0 assert all(v == 0.0 for v in result.values()) def test_none_data_returns_zeros(self): """None 数据应返回全 0。""" result = calculate_health_score(None) assert result["total_score"] == 0.0 def test_full_14_dimensions_present(self): """完整数据应返回 14 个维度分数 + total_score。""" data = { "cash_balance": {"runway_months": 18}, "revenue": {"yoy_change": "+30%"}, "burn_rate": {"trend": "down"}, "headcount": {"new_hires": 5, "departures": 1, "total": 50}, "key_metrics": [ {"name": "MAU", "change": "+15%"}, {"name": "产品迭代次数", "change": "+10%"}, {"name": "AI 推理成本", "change": "-5%"}, ], "governance": {"board_meeting_held": True, "compliance_issues": False}, "financing": {"in_progress": True}, "synergy": {"active_count": 3, "completed_count": 2}, "ai_metrics": {"model_accuracy": 0.95, "inference_cost_trend": "down", "data_quality_score": 80}, "data_compliance": {"issues_count": 0, "audit_passed": True}, "team_tech": {"tech_lead_count": 3, "patent_count": 5}, "customer_success": {"retention_rate": 0.92, "nps": 50}, } result = calculate_health_score(data) expected_keys = [ "total_score", "financial_score", "operational_score", "ai_commercial_score", "ai_cost_score", "org_talent_score", "product_tech_score", "market_compete_score", "governance_score", "financing_score", "synergy_score", "ai_model_product_score", "data_compliance_score", "team_tech_score", "customer_success_score", ] assert all(k in result for k in expected_keys) assert 0 <= result["total_score"] <= 100 def test_financial_score_high_runway(self): """长跑道应得高分。""" data = {"cash_balance": {"runway_months": 15}, "revenue": {"yoy_change": "+20%"}, "burn_rate": {"trend": "down"}} score = _calc_financial_score(data) assert score >= 80 def test_financial_score_low_runway(self): """短跑道应得低分。""" data = {"cash_balance": {"runway_months": 2}, "revenue": {"yoy_change": "-10%"}, "burn_rate": {"trend": "up"}} score = _calc_financial_score(data) assert score < 40 def test_org_talent_low_turnover(self): """低流失率应得高分。""" data = {"headcount": {"new_hires": 3, "departures": 1, "total": 50}} score = _calc_org_talent_score(data) assert score >= 75 def test_org_talent_high_turnover(self): """高流失率应得低分。""" data = {"headcount": {"new_hires": 1, "departures": 12, "total": 50}} score = _calc_org_talent_score(data) assert score <= 50 def test_product_tech_positive_growth(self): """产品技术指标正增长应加分。""" data = {"key_metrics": [{"name": "产品迭代次数", "change": "+20%"}]} score = _calc_product_tech_score(data) assert score > 55 def test_market_compete_positive(self): """市场竞争指标正增长应加分。""" data = {"key_metrics": [{"name": "MAU", "change": "+25%"}]} score = _calc_market_compete_score(data) assert score > 55 def test_governance_with_compliance_issues(self): """有合规问题应减分。""" data = {"governance": {"board_meeting_held": True, "compliance_issues": True}} score = _calc_governance_score(data) assert score < 70 def test_financing_long_runway(self): """长跑道 + 融资进行中应得高分。""" data = {"cash_balance": {"runway_months": 20}, "financing": {"in_progress": True}} score = _calc_financing_score(data) assert score >= 80 def test_synergy_active(self): """有活跃协同应加分。""" data = {"synergy": {"active_count": 4, "completed_count": 2}} score = _calc_synergy_score(data) assert score > 55 def test_ai_model_product_high_accuracy(self): """AI 模型高准确率应加分。""" data = {"ai_metrics": {"model_accuracy": 0.95, "inference_cost_trend": "down", "data_quality_score": 85}} score = _calc_ai_model_product_score(data) assert score > 50 def test_data_compliance_no_issues(self): """无合规问题 + 审计通过应得高分。""" data = {"data_compliance": {"issues_count": 0, "audit_passed": True}} score = _calc_data_compliance_score(data) assert score >= 80 def test_data_compliance_with_issues(self): """有合规问题应减分。""" data = {"data_compliance": {"issues_count": 3, "audit_passed": False}} score = _calc_data_compliance_score(data) assert score < 50 def test_team_tech_with_leads_and_patents(self): """有技术负责人和专利应加分。""" data = {"team_tech": {"tech_lead_count": 3, "patent_count": 5}} score = _calc_team_tech_score(data) assert score > 55 def test_customer_success_high_retention(self): """高留存率应得高分。""" data = {"customer_success": {"retention_rate": 0.95, "nps": 60}} score = _calc_customer_success_score(data) assert score >= 75 def test_customer_success_low_retention(self): """低留存率应得低分。""" data = {"customer_success": {"retention_rate": 0.60, "nps": 10}} score = _calc_customer_success_score(data) assert score < 50 def test_total_score_in_range(self): """总分应在 0-100 范围内。""" data = { "cash_balance": {"runway_months": 6}, "headcount": {"new_hires": 2, "departures": 1, "total": 30}, "key_metrics": [{"name": "营收", "change": "+5%"}], } result = calculate_health_score(data) assert 0 <= result["total_score"] <= 100 class TestDetermineTrend: """趋势判断测试。""" def test_up_trend(self): assert determine_trend(80, 70) == "up" def test_down_trend(self): assert determine_trend(60, 70) == "down" def test_stable_trend(self): assert determine_trend(70, 72) == "stable" def test_no_previous(self): assert determine_trend(70, None) == "stable"