300 lines
10 KiB
Python
300 lines
10 KiB
Python
"""评价指标体系 API 集成测试。"""
|
|
|
|
from fastapi.testclient import TestClient
|
|
|
|
|
|
class TestWeightComputeAPI:
|
|
"""权重计算 API 测试。"""
|
|
|
|
def test_compute_weights_success(self, client: TestClient, auth_headers: dict):
|
|
"""POST /evaluation/weights/compute 应返回权重计算结果。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/weights/compute",
|
|
json={
|
|
"fund_type": "early_vc",
|
|
"fund_lifecycle": "investment",
|
|
"company_stage": "a",
|
|
"industry": "ai",
|
|
"strategy": "growth",
|
|
"investor_type": "investor",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "weights" in data
|
|
assert "enabled_dimensions" in data
|
|
assert "disabled_dimensions" in data
|
|
assert "custom_metrics" in data
|
|
# 权重总和应接近 100
|
|
total = sum(data["weights"].values())
|
|
assert abs(total - 100.0) < 1.0
|
|
|
|
def test_compute_weights_no_auth(self, client: TestClient):
|
|
"""未认证应返回 401。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/weights/compute",
|
|
json={
|
|
"fund_type": "early_vc",
|
|
"company_stage": "a",
|
|
"industry": "ai",
|
|
},
|
|
)
|
|
assert resp.status_code == 401
|
|
|
|
def test_compute_weights_hardware_disables_ai(self, client: TestClient, auth_headers: dict):
|
|
"""硬科技赛道应禁用 AI 维度。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/weights/compute",
|
|
json={
|
|
"fund_type": "early_vc",
|
|
"fund_lifecycle": "investment",
|
|
"company_stage": "a",
|
|
"industry": "hardware",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "ai_commercial" in data["disabled_dimensions"]
|
|
assert "ai_cost" in data["disabled_dimensions"]
|
|
|
|
|
|
class TestTemplateAPI:
|
|
"""评价模板 API 测试。"""
|
|
|
|
def test_list_templates_empty(self, client: TestClient, auth_headers: dict):
|
|
"""无模板时应返回空列表。"""
|
|
resp = client.get("/api/v1/evaluation/templates", headers=auth_headers)
|
|
assert resp.status_code == 200
|
|
assert isinstance(resp.json()["data"], list)
|
|
|
|
def test_list_templates_no_auth(self, client: TestClient):
|
|
"""未认证应返回 401。"""
|
|
resp = client.get("/api/v1/evaluation/templates")
|
|
assert resp.status_code == 401
|
|
|
|
def test_create_template_auto_weights(self, client: TestClient, auth_headers: dict):
|
|
"""创建模板时不传权重应自动计算。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "测试模板-早期VC-AI",
|
|
"fund_type": "early_vc",
|
|
"fund_lifecycle": "investment",
|
|
"company_stage": "a",
|
|
"industry": "ai",
|
|
"strategy": "growth",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "id" in data
|
|
assert "weights" in data
|
|
|
|
def test_create_template_with_custom_weights(self, client: TestClient, auth_headers: dict):
|
|
"""创建模板时传自定义权重应使用自定义权重。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "自定义权重模板",
|
|
"fund_type": "early_vc",
|
|
"fund_lifecycle": "growth",
|
|
"company_stage": "b",
|
|
"industry": "saas",
|
|
"strategy": "value",
|
|
"weights_json": {"financial": 40, "product_tech": 30, "market_compete": 30},
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert data["weights"]["financial"] == 40
|
|
|
|
def test_get_template_by_id(self, client: TestClient, auth_headers: dict):
|
|
"""根据 ID 获取模板详情。"""
|
|
# 先创建
|
|
create_resp = client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "查询测试模板",
|
|
"fund_type": "pe",
|
|
"fund_lifecycle": "growth",
|
|
"company_stage": "c",
|
|
"industry": "fintech",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
template_id = create_resp.json()["data"]["id"]
|
|
|
|
# 再查询
|
|
resp = client.get(f"/api/v1/evaluation/templates/{template_id}", headers=auth_headers)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert data["name"] == "查询测试模板"
|
|
assert data["fund_type"] == "pe"
|
|
|
|
def test_get_template_not_found(self, client: TestClient, auth_headers: dict):
|
|
"""查询不存在的模板应返回 404。"""
|
|
resp = client.get(
|
|
"/api/v1/evaluation/templates/nonexistent-id",
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
assert resp.json()["code"] == 404
|
|
|
|
def test_list_templates_with_filter(self, client: TestClient, auth_headers: dict):
|
|
"""按基金类型筛选模板。"""
|
|
# 创建两个不同类型模板
|
|
client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "筛选-早期VC",
|
|
"fund_type": "early_vc",
|
|
"company_stage": "a",
|
|
"industry": "ai",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "筛选-PE",
|
|
"fund_type": "pe",
|
|
"company_stage": "b",
|
|
"industry": "saas",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
|
|
resp = client.get(
|
|
"/api/v1/evaluation/templates?fund_type=pe",
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
for tmpl in data:
|
|
assert tmpl["fund_type"] == "pe"
|
|
|
|
|
|
class TestScoreCalculateAPI:
|
|
"""评分计算 API 测试。"""
|
|
|
|
def test_calculate_score_without_template(self, client: TestClient, auth_headers: dict, company_id: str):
|
|
"""无模板时计算评分应使用默认计算。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/score",
|
|
json={
|
|
"company_id": company_id,
|
|
"structured_data": {
|
|
"revenue": {"yoy_change": "30"},
|
|
"cash_balance": {"runway_months": 18},
|
|
"burn_rate": {"trend": "down"},
|
|
},
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "total_score" in data
|
|
assert "dimension_scores" in data
|
|
|
|
def test_calculate_score_no_auth(self, client: TestClient):
|
|
"""未认证应返回 401。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/score",
|
|
json={"company_id": "test", "structured_data": {}},
|
|
)
|
|
assert resp.status_code == 401
|
|
|
|
def test_calculate_score_with_template(self, client: TestClient, auth_headers: dict, company_id: str):
|
|
"""使用模板计算评分。"""
|
|
# 先创建模板
|
|
tmpl_resp = client.post(
|
|
"/api/v1/evaluation/templates",
|
|
json={
|
|
"name": "评分测试模板",
|
|
"fund_type": "early_vc",
|
|
"company_stage": "a",
|
|
"industry": "ai",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
template_id = tmpl_resp.json()["data"]["id"]
|
|
|
|
# 使用模板计算评分
|
|
resp = client.post(
|
|
"/api/v1/evaluation/score",
|
|
json={
|
|
"company_id": company_id,
|
|
"template_id": template_id,
|
|
"structured_data": {
|
|
"revenue": {"yoy_change": "25"},
|
|
"cash_balance": {"runway_months": 15},
|
|
"burn_rate": {"trend": "down"},
|
|
"headcount": {"new_hires": 3, "departures": 1},
|
|
},
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "score_id" in data
|
|
assert "total_score" in data
|
|
assert data["template"] is not None
|
|
assert data["template"]["id"] == template_id
|
|
|
|
|
|
class TestScoreHistoryAPI:
|
|
"""评分历史 API 测试。"""
|
|
|
|
def test_list_scores_empty(self, client: TestClient, auth_headers: dict):
|
|
"""无评分记录时应返回空列表。"""
|
|
resp = client.get("/api/v1/evaluation/scores", headers=auth_headers)
|
|
assert resp.status_code == 200
|
|
assert isinstance(resp.json()["data"], list)
|
|
|
|
def test_list_scores_no_auth(self, client: TestClient):
|
|
"""未认证应返回 401。"""
|
|
resp = client.get("/api/v1/evaluation/scores")
|
|
assert resp.status_code == 401
|
|
|
|
|
|
class TestFundAPI:
|
|
"""基金管理 API 测试。"""
|
|
|
|
def test_list_funds_empty(self, client: TestClient, auth_headers: dict):
|
|
"""无基金时应返回空列表。"""
|
|
resp = client.get("/api/v1/evaluation/funds", headers=auth_headers)
|
|
assert resp.status_code == 200
|
|
assert isinstance(resp.json()["data"], list)
|
|
|
|
def test_create_fund(self, client: TestClient, auth_headers: dict):
|
|
"""创建基金。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/funds",
|
|
json={
|
|
"name": "测试基金一期",
|
|
"fund_type": "early_vc",
|
|
"strategy": "growth",
|
|
"established_date": "2023-01-01",
|
|
"total_lifespan_months": 84,
|
|
"investment_period_months": 48,
|
|
"primary_market": "china_mainland",
|
|
},
|
|
headers=auth_headers,
|
|
)
|
|
assert resp.status_code == 200
|
|
data = resp.json()["data"]
|
|
assert "id" in data
|
|
assert data["current_lifecycle"] == "investment"
|
|
|
|
def test_create_fund_no_auth(self, client: TestClient):
|
|
"""未认证应返回 401。"""
|
|
resp = client.post(
|
|
"/api/v1/evaluation/funds",
|
|
json={"name": "test", "fund_type": "early_vc"},
|
|
)
|
|
assert resp.status_code == 401
|