Files
AIPortPilot/backend/tests/test_company_detail.py
T
selfrelease fad458b2a7 docs(uiux): UIUX 设计方案大改 + 5 份作业指导书对齐 + 开发任务文档
- UIUX 文档:填充 19 个缺口(多主体画像/健康度/AI+看板/增长域/洞察域/创始人端/OODA/助推/商密)
- UIUX 文档:插入 6 个新章节(十四~十九),旧章节重编号为二十~三十一,更新目录和交叉引用
- 作业指导书 x5:导航改为 6 域分组,新增 Context Bar/工作模式/Insight Rail/决策线程/多工作区等 UI 概念
- 新建 docs/2-task-uiux.md:50 个代码落地开发任务,按 P0-P6 分优先级 + 8 Sprint 规划
- 后端/前端:大量新增模型、路由、组件(来自之前 Phase 开发)
2026-07-19 11:53:38 +08:00

220 lines
8.6 KiB
Python

"""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"