feat: P0/P1/P2全部功能 — 四层泳道/视角切换/KPI看板/预警/差异反打/预算/知识面板/回顾会/情景预测/Excel导入/角色权限
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
"""
|
||||
AI分析引擎/CEO简报模块测试
|
||||
"""
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
from sqlalchemy.orm import Session
|
||||
from datetime import datetime
|
||||
from tests.conftest import create_test_user, get_token_for_user, auth_header, create_test_kpi
|
||||
from app.models import KPIAlert, KPIValue, ActionPlan
|
||||
|
||||
|
||||
class TestAiAnalysis:
|
||||
"""AI分析/CEO简报测试"""
|
||||
|
||||
def test_brief_no_data(self, client: TestClient, db: Session):
|
||||
"""无数据时简报返回暂无数据"""
|
||||
create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
|
||||
resp = client.get("/api/cma/ai/brief", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["brief"]["conclusion"] == "暂无数据,无法生成简报"
|
||||
assert data["brief"]["concerns"] == []
|
||||
assert data["brief"]["actions"] == []
|
||||
|
||||
def test_brief_with_data(self, client: TestClient, db: Session):
|
||||
"""有KPI数据时简报正常生成(不调用AI,因为AI会超时但应正常返回)"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
kpi = create_test_kpi(db)
|
||||
kpi_val = KPIValue(kpi_id=kpi.id, period="2026-06", actual_value=85.0)
|
||||
db.add(kpi_val)
|
||||
db.commit()
|
||||
|
||||
# 请求简报——由于没有真正的 DeepSeek API key,会返回错误文本但不会崩溃
|
||||
resp = client.get("/api/cma/ai/brief?timeout=5", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
# 确保返回结构完整
|
||||
assert "brief" in data
|
||||
assert "generated_at" in data
|
||||
# 可能因为无实际API key而返回错误,但不会崩溃
|
||||
assert isinstance(data["brief"]["concerns"], list)
|
||||
assert isinstance(data["brief"]["actions"], list)
|
||||
|
||||
def test_dashboard_analysis_no_data(self, client: TestClient, db: Session):
|
||||
"""无数据时AI驾驶舱分析"""
|
||||
create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
|
||||
resp = client.get("/api/cma/ai/dashboard-analysis", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "analysis" in data
|
||||
assert data["kpi_count"] == 0
|
||||
assert data["alert_count"] == 0
|
||||
|
||||
def test_dashboard_analysis_with_kpi(self, client: TestClient, db: Session):
|
||||
"""有KPI数据时驾驶舱分析正常返回"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
kpi = create_test_kpi(db)
|
||||
kpi_val = KPIValue(kpi_id=kpi.id, period="2026-06", actual_value=90.0)
|
||||
db.add(kpi_val)
|
||||
db.commit()
|
||||
|
||||
resp = client.get("/api/cma/ai/dashboard-analysis", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["kpi_count"] == 1
|
||||
|
||||
def test_kpi_analysis_not_found(self, client: TestClient, db: Session):
|
||||
"""分析不存在的KPI"""
|
||||
create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
|
||||
resp = client.get("/api/cma/ai/kpi-analysis/9999", headers=auth_header(token))
|
||||
assert resp.status_code == 404
|
||||
|
||||
def test_kpi_analysis_success(self, client: TestClient, db: Session):
|
||||
"""分析单个KPI"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
kpi = create_test_kpi(db)
|
||||
kpi_val = KPIValue(kpi_id=kpi.id, period="2026-04", actual_value=80.0)
|
||||
db.add(kpi_val)
|
||||
kpi_val2 = KPIValue(kpi_id=kpi.id, period="2026-05", actual_value=85.0)
|
||||
db.add(kpi_val2)
|
||||
kpi_val3 = KPIValue(kpi_id=kpi.id, period="2026-06", actual_value=90.0)
|
||||
db.add(kpi_val3)
|
||||
db.commit()
|
||||
|
||||
resp = client.get(f"/api/cma/ai/kpi-analysis/{kpi.id}", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert data["kpi_name"] == "测试KPI"
|
||||
assert "analysis" in data
|
||||
|
||||
def test_review_plans_empty(self, client: TestClient, db: Session):
|
||||
"""无改善计划时的复盘"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
create_test_user(db, username="ceo_user", name="CEO用户", role="ceo")
|
||||
|
||||
resp = client.post("/api/cma/ai/review-plans", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
assert "暂无改善行动计划" in resp.json()["analysis"]
|
||||
|
||||
def test_review_plans_with_data(self, client: TestClient, db: Session):
|
||||
"""有改善计划时的复盘"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
kpi = create_test_kpi(db)
|
||||
plan = ActionPlan(
|
||||
alert_id=None,
|
||||
kpi_id=kpi.id,
|
||||
title="提升营收10%",
|
||||
assignee="张三",
|
||||
priority="high",
|
||||
status="in_progress",
|
||||
progress=50,
|
||||
created_by="系统",
|
||||
)
|
||||
db.add(plan)
|
||||
db.commit()
|
||||
|
||||
resp = client.post("/api/cma/ai/review-plans", headers=auth_header(token))
|
||||
assert resp.status_code == 200
|
||||
data = resp.json()
|
||||
assert "analysis" in data
|
||||
assert data["stats"]["total"] == 1
|
||||
assert data["stats"]["in_progress"] == 1
|
||||
|
||||
def test_ask_empty_question(self, client: TestClient, db: Session):
|
||||
"""空问题被拒绝"""
|
||||
user = create_test_user(db)
|
||||
token = get_token_for_user(client)
|
||||
|
||||
resp = client.post(
|
||||
"/api/cma/ai/ask",
|
||||
headers=auth_header(token),
|
||||
json={"question": ""},
|
||||
)
|
||||
assert resp.status_code == 400
|
||||
Reference in New Issue
Block a user