773 lines
24 KiB
Python
773 lines
24 KiB
Python
# =============================================================================
|
||
# 企微IT智能服务台 — 满意度评价功能测试 (P1-25)
|
||
# =============================================================================
|
||
# 测试范围:
|
||
# 1. POST /conversation/{conversation_id}/evaluate - 提交评价
|
||
# 2. GET /conversation/{conversation_id}/evaluation - 获取会话评价
|
||
# 3. GET /api/evaluations/stats - 获取评价统计
|
||
# 4. POST /conversations/{conversation_id}/send-evaluation-invite - 发送评价邀请
|
||
# =============================================================================
|
||
|
||
import pytest
|
||
import pytest_asyncio
|
||
from datetime import datetime
|
||
from unittest.mock import patch, AsyncMock
|
||
|
||
from sqlalchemy import select
|
||
|
||
from app.models.conversation import Conversation
|
||
from app.models.employee import Employee
|
||
from app.models.agent import Agent
|
||
from app.models.role import Role
|
||
from app.models.user_role import UserRole
|
||
from app.models.conversation_evaluation import ConversationEvaluation
|
||
|
||
|
||
def create_test_employee(
|
||
db_session,
|
||
employee_id: str = "test_employee_001",
|
||
name: str = "测试员工",
|
||
corp_id: str = "test_corp_id",
|
||
):
|
||
"""创建测试员工"""
|
||
employee = Employee(
|
||
employee_id=employee_id,
|
||
name=name,
|
||
corp_id=corp_id,
|
||
department="技术部",
|
||
position="工程师",
|
||
status=1,
|
||
)
|
||
db_session.add(employee)
|
||
return employee
|
||
|
||
|
||
# =============================================================================
|
||
# 测试用例:提交评价 (POST /conversation/{conversation_id}/evaluate)
|
||
# =============================================================================
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_success(client, db_session, mock_redis):
|
||
"""测试成功提交满意度评价"""
|
||
# 1. 创建测试会话(状态为 resolved)
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 2. 创建员工记录
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
# 3. 模拟 H5 员工登录 - 使用 Redis Token
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 5,
|
||
"emoji": "satisfied",
|
||
"feedback_text": "服务态度很好!",
|
||
},
|
||
)
|
||
|
||
# 4. 验证响应
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
assert data["data"]["star_rating"] == 5
|
||
assert data["data"]["emoji"] == "satisfied"
|
||
assert data["data"]["feedback_text"] == "服务态度很好!"
|
||
assert data["data"]["employee_id"] == "test_employee_001"
|
||
assert data["data"]["conversation_id"] == conversation.id
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_invalid_star_rating(client, db_session, mock_redis):
|
||
"""测试提交评价时星级超出范围(1-5)"""
|
||
# 创建测试会话
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
# 提交星级为 0(超出范围)
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 0, # 无效:小于1
|
||
"emoji": "satisfied",
|
||
},
|
||
)
|
||
|
||
# 应该返回 422 验证错误
|
||
assert response.status_code == 422
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_conversation_not_resolved(client, db_session, mock_redis):
|
||
"""测试只能评价已结单的会话"""
|
||
# 创建未结单的会话
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="serving", # 未结单
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 5,
|
||
"emoji": "satisfied",
|
||
},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3040 # 只能评价已结单的会话
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_duplicate(client, db_session, mock_redis):
|
||
"""测试重复评价(防止重复提交)"""
|
||
# 创建测试会话
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 创建员工
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
# 创建已有评价
|
||
evaluation = ConversationEvaluation(
|
||
conversation_id=conversation.id,
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
star_rating=5,
|
||
emoji="satisfied",
|
||
)
|
||
db_session.add(evaluation)
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
# 再次提交评价
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 4,
|
||
"emoji": "neutral",
|
||
},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3041 # 您已对该会话提交过评价
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_conversation_not_found(client, db_session, mock_redis):
|
||
"""测试评价不存在的会话"""
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
response = await client.post(
|
||
"/conversation/nonexistent-id/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 5,
|
||
"emoji": "satisfied",
|
||
},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3003 # 会话不存在
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_all_emoji_options(client, db_session, mock_redis):
|
||
"""测试所有表情选项"""
|
||
# Test satisfied
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 5,
|
||
"emoji": "satisfied",
|
||
},
|
||
)
|
||
assert response.status_code == 200
|
||
assert response.json()["data"]["emoji"] == "satisfied"
|
||
|
||
# Create new conversation to test neutral
|
||
conversation2 = Conversation(
|
||
employee_id="test_employee_002",
|
||
employee_name="测试员工2",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation2)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_002")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_002", 28800, "test_employee_002")
|
||
|
||
response = await client.post(
|
||
f"/conversation/{conversation2.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_002"},
|
||
json={
|
||
"star_rating": 3,
|
||
"emoji": "neutral",
|
||
},
|
||
)
|
||
assert response.status_code == 200
|
||
assert response.json()["data"]["emoji"] == "neutral"
|
||
|
||
# Create new conversation to test dissatisfied
|
||
conversation3 = Conversation(
|
||
employee_id="test_employee_003",
|
||
employee_name="测试员工3",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation3)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_003")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_003", 28800, "test_employee_003")
|
||
|
||
response = await client.post(
|
||
f"/conversation/{conversation3.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_003"},
|
||
json={
|
||
"star_rating": 1,
|
||
"emoji": "dissatisfied",
|
||
},
|
||
)
|
||
assert response.status_code == 200
|
||
assert response.json()["data"]["emoji"] == "dissatisfied"
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_submit_evaluation_feedback_text_optional(client, db_session, mock_redis):
|
||
"""测试文字反馈为可选字段"""
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
create_test_employee(db_session, employee_id="test_employee_001")
|
||
await db_session.flush()
|
||
|
||
await mock_redis.setex("employee:token:test_token_001", 28800, "test_employee_001")
|
||
|
||
# 不提供 feedback_text
|
||
response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_001"},
|
||
json={
|
||
"star_rating": 4,
|
||
"emoji": "satisfied",
|
||
},
|
||
)
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["data"]["feedback_text"] is None
|
||
|
||
|
||
# =============================================================================
|
||
# 测试用例:获取会话评价 (GET /conversation/{conversation_id}/evaluation)
|
||
# =============================================================================
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_evaluation_success(client, db_session):
|
||
"""测试获取会话评价 - 存在评价"""
|
||
# 创建会话和评价
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
evaluation = ConversationEvaluation(
|
||
conversation_id=conversation.id,
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
star_rating=5,
|
||
emoji="satisfied",
|
||
feedback_text="很好!",
|
||
)
|
||
db_session.add(evaluation)
|
||
await db_session.flush()
|
||
|
||
# 获取评价
|
||
response = await client.get(f"/conversation/{conversation.id}/evaluation")
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
assert data["data"]["star_rating"] == 5
|
||
assert data["data"]["emoji"] == "satisfied"
|
||
assert data["data"]["feedback_text"] == "很好!"
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_evaluation_not_found(client, db_session):
|
||
"""测试获取会话评价 - 不存在"""
|
||
# 创建会话但没有评价
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 获取评价
|
||
response = await client.get(f"/conversation/{conversation.id}/evaluation")
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
assert data["data"] is None # 没有评价时返回 null
|
||
|
||
|
||
# =============================================================================
|
||
# 测试用例:获取评价统计 (GET /api/evaluations/stats)
|
||
# =============================================================================
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_evaluation_stats_success(client, db_session):
|
||
"""测试获取评价统计 - 有数据"""
|
||
# 创建多个会话和评价
|
||
for i in range(5):
|
||
conv = Conversation(
|
||
employee_id=f"test_employee_{i:03d}",
|
||
employee_name=f"测试员工{i}",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conv)
|
||
await db_session.flush()
|
||
|
||
# 3个5星满意, 1个3星一般, 1个1星不满意
|
||
if i < 3:
|
||
star, emoji = 5, "satisfied"
|
||
elif i == 3:
|
||
star, emoji = 3, "neutral"
|
||
else:
|
||
star, emoji = 1, "dissatisfied"
|
||
|
||
eval = ConversationEvaluation(
|
||
conversation_id=conv.id,
|
||
employee_id=f"test_employee_{i:03d}",
|
||
employee_name=f"测试员工{i}",
|
||
star_rating=star,
|
||
emoji=emoji,
|
||
)
|
||
db_session.add(eval)
|
||
await db_session.flush()
|
||
|
||
# 需要管理员权限才能访问统计接口
|
||
# 先创建管理员角色
|
||
role_stmt = select(Role).where(Role.name == "admin")
|
||
role_result = await db_session.execute(role_stmt)
|
||
admin_role = role_result.scalars().first()
|
||
if not admin_role:
|
||
admin_role = Role(
|
||
name="admin",
|
||
display_name="管理员",
|
||
description="管理员角色",
|
||
permissions=["evaluation:read:all"],
|
||
)
|
||
db_session.add(admin_role)
|
||
await db_session.flush()
|
||
|
||
# 为测试坐席添加管理员角色
|
||
agent = Agent(
|
||
user_id="test_agent_admin",
|
||
name="测试管理员",
|
||
status="online",
|
||
)
|
||
db_session.add(agent)
|
||
await db_session.flush()
|
||
|
||
user_role = UserRole(
|
||
employee_id="test_agent_admin",
|
||
role_id=admin_role.id,
|
||
source="manual",
|
||
assigned_by="test",
|
||
)
|
||
db_session.add(user_role)
|
||
await db_session.flush()
|
||
|
||
# 登录获取 token
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_admin",
|
||
"name": "测试管理员",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 获取统计
|
||
response = await client.get(
|
||
"/evaluations/stats",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
|
||
stats = data["data"]
|
||
assert stats["total_count"] == 5
|
||
# (5+5+5+3+1)/5 = 3.8
|
||
assert abs(stats["avg_star_rating"] - 3.8) < 0.01
|
||
|
||
# 验证星级分布
|
||
star_dist = {item["label"]: item for item in stats["star_distribution"]}
|
||
assert star_dist["5星"]["count"] == 3
|
||
assert star_dist["3星"]["count"] == 1
|
||
assert star_dist["1星"]["count"] == 1
|
||
|
||
# 验证表情分布
|
||
emoji_dist = {item["label"]: item for item in stats["emoji_distribution"]}
|
||
assert emoji_dist["满意"]["count"] == 3
|
||
assert emoji_dist["一般"]["count"] == 1
|
||
assert emoji_dist["不满意"]["count"] == 1
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_get_evaluation_stats_empty(client, db_session):
|
||
"""测试获取评价统计 - 无数据"""
|
||
# 需要管理员权限
|
||
role_stmt = select(Role).where(Role.name == "admin")
|
||
role_result = await db_session.execute(role_stmt)
|
||
admin_role = role_result.scalars().first()
|
||
if not admin_role:
|
||
admin_role = Role(
|
||
name="admin",
|
||
display_name="管理员",
|
||
description="管理员角色",
|
||
permissions=["evaluation:read:all"],
|
||
)
|
||
db_session.add(admin_role)
|
||
await db_session.flush()
|
||
|
||
agent = Agent(
|
||
user_id="test_agent_admin",
|
||
name="测试管理员",
|
||
status="online",
|
||
)
|
||
db_session.add(agent)
|
||
await db_session.flush()
|
||
|
||
user_role = UserRole(
|
||
employee_id="test_agent_admin",
|
||
role_id=admin_role.id,
|
||
source="manual",
|
||
assigned_by="test",
|
||
)
|
||
db_session.add(user_role)
|
||
await db_session.flush()
|
||
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_admin",
|
||
"name": "测试管理员",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 获取统计(无数据)
|
||
response = await client.get(
|
||
"/evaluations/stats",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
|
||
stats = data["data"]
|
||
assert stats["total_count"] == 0
|
||
assert stats["avg_star_rating"] == 0.0
|
||
assert stats["star_distribution"][0]["count"] == 0
|
||
|
||
|
||
# =============================================================================
|
||
# 测试用例:发送评价邀请 (POST /conversations/{conversation_id}/send-evaluation-invite)
|
||
# =============================================================================
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_evaluation_invite_success(client, db_session, mock_redis):
|
||
"""测试发送评价邀请 - 成功"""
|
||
# 创建会话(已结单)
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 登录坐席获取 token
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_001",
|
||
"name": "测试坐席",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 发送评价邀请
|
||
response = await client.post(
|
||
f"/conversations/{conversation.id}/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 0
|
||
assert "评价邀请已发送" in data["data"]["message"]
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_evaluation_invite_conversation_not_resolved(client, db_session):
|
||
"""测试只能对已结单的会话发送评价邀请"""
|
||
# 创建未结单的会话
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="serving", # 未结单
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 登录坐席
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_001",
|
||
"name": "测试坐席",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 发送评价邀请
|
||
response = await client.post(
|
||
f"/conversations/{conversation.id}/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3042 # 只能对已结单的会话发送评价邀请
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_evaluation_invite_already_evaluated(client, db_session):
|
||
"""测试该会话已收到评价时不能再发送邀请"""
|
||
# 创建会话和评价
|
||
conversation = Conversation(
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 已有评价
|
||
evaluation = ConversationEvaluation(
|
||
conversation_id=conversation.id,
|
||
employee_id="test_employee_001",
|
||
employee_name="测试员工",
|
||
star_rating=5,
|
||
emoji="satisfied",
|
||
)
|
||
db_session.add(evaluation)
|
||
await db_session.flush()
|
||
|
||
# 登录坐席
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_001",
|
||
"name": "测试坐席",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 发送评价邀请
|
||
response = await client.post(
|
||
f"/conversations/{conversation.id}/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3043 # 该会话已收到评价,无需再次邀请
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_send_evaluation_invite_conversation_not_found(client, db_session):
|
||
"""测试发送评价邀请时会话不存在"""
|
||
# 登录坐席
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_001",
|
||
"name": "测试坐席",
|
||
})
|
||
token = login_response.json()["data"]["token"]
|
||
|
||
# 发送评价邀请
|
||
response = await client.post(
|
||
"/conversations/nonexistent-id/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
# 应该返回错误
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["code"] == 3003 # 会话不存在
|
||
|
||
|
||
# =============================================================================
|
||
# 测试用例:端到端流程测试
|
||
# =============================================================================
|
||
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_evaluation_full_flow(client, db_session, mock_redis):
|
||
"""测试完整流程:会话结单 -> 发送评价邀请 -> 提交评价 -> 查看评价 -> 统计"""
|
||
# 1. 创建会话
|
||
conversation = Conversation(
|
||
employee_id="test_employee_flow",
|
||
employee_name="流程测试员工",
|
||
status="resolved",
|
||
department="技术部",
|
||
position="工程师",
|
||
)
|
||
db_session.add(conversation)
|
||
await db_session.flush()
|
||
|
||
# 创建员工
|
||
create_test_employee(db_session, employee_id="test_employee_flow")
|
||
await db_session.flush()
|
||
|
||
# 2. 坐席发送评价邀请
|
||
login_response = await client.post("/agents/login", json={
|
||
"user_id": "test_agent_flow",
|
||
"name": "流程测试坐席",
|
||
})
|
||
agent_token = login_response.json()["data"]["token"]
|
||
|
||
invite_response = await client.post(
|
||
f"/conversations/{conversation.id}/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {agent_token}"},
|
||
)
|
||
assert invite_response.status_code == 200
|
||
assert invite_response.json()["code"] == 0
|
||
|
||
# 3. 员工提交评价
|
||
await mock_redis.setex("employee:token:test_token_flow", 28800, "test_employee_flow")
|
||
|
||
eval_response = await client.post(
|
||
f"/conversation/{conversation.id}/evaluate",
|
||
headers={"Authorization": "Bearer test_token_flow"},
|
||
json={
|
||
"star_rating": 4,
|
||
"emoji": "satisfied",
|
||
"feedback_text": "服务很专业!",
|
||
},
|
||
)
|
||
assert eval_response.status_code == 200
|
||
assert eval_response.json()["code"] == 0
|
||
assert eval_response.json()["data"]["star_rating"] == 4
|
||
|
||
# 4. 查看会话评价
|
||
get_response = await client.get(f"/conversation/{conversation.id}/evaluation")
|
||
assert get_response.status_code == 200
|
||
assert get_response.json()["code"] == 0
|
||
assert get_response.json()["data"]["star_rating"] == 4
|
||
|
||
# 5. 尝试再次发送邀请(应该失败)
|
||
invite_again_response = await client.post(
|
||
f"/conversations/{conversation.id}/send-evaluation-invite",
|
||
headers={"Authorization": f"Bearer {agent_token}"},
|
||
)
|
||
assert invite_again_response.status_code == 200
|
||
assert invite_again_response.json()["code"] == 3043
|