144 lines
4.8 KiB
Python
144 lines
4.8 KiB
Python
# =============================================================================
|
||
# 企微IT智能服务台 — API 基础验证测试
|
||
# =============================================================================
|
||
# 测试覆盖:
|
||
# 1. 健康检查端点
|
||
# 2. 统一响应格式(code/data/message)
|
||
# 3. CORS 配置
|
||
# 4. 404 路由
|
||
# 5. AppException 全局异常处理
|
||
# 6. success_response / error_response 工具函数
|
||
# =============================================================================
|
||
|
||
import pytest
|
||
import pytest_asyncio
|
||
|
||
from app.utils.response import success_response, error_response, AppException
|
||
|
||
|
||
class TestHealthCheck:
|
||
"""测试健康检查端点。"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_health_check(self, client, db_session):
|
||
"""验证 /health 端点返回正常状态。"""
|
||
response = await client.get("/health")
|
||
|
||
assert response.status_code == 200
|
||
data = response.json()
|
||
assert data["status"] == "ok"
|
||
assert "service" in data
|
||
|
||
|
||
class TestUnifiedResponseFormat:
|
||
"""测试统一响应格式。"""
|
||
|
||
def test_success_response_format(self):
|
||
"""验证成功响应格式:{code: 0, data: {}, message: "success"}。"""
|
||
result = success_response(data={"key": "value"})
|
||
|
||
assert result["code"] == 0
|
||
assert result["data"] == {"key": "value"}
|
||
assert result["message"] == "success"
|
||
|
||
def test_success_response_default_data(self):
|
||
"""验证成功响应默认 data 为 None。"""
|
||
result = success_response()
|
||
|
||
assert result["code"] == 0
|
||
assert result["data"] is None
|
||
|
||
def test_success_response_custom_message(self):
|
||
"""验证成功响应自定义消息。"""
|
||
result = success_response(message="操作成功")
|
||
|
||
assert result["message"] == "操作成功"
|
||
|
||
def test_error_response_format(self):
|
||
"""验证错误响应格式:{code: N, data: null, message: "错误信息"}。"""
|
||
result = error_response(1001, "参数错误")
|
||
|
||
assert result["code"] == 1001
|
||
assert result["data"] is None
|
||
assert result["message"] == "参数错误"
|
||
|
||
def test_error_response_with_data(self):
|
||
"""验证错误响应可附带额外数据。"""
|
||
result = error_response(1001, "校验失败", data={"field": "email"})
|
||
|
||
assert result["data"] == {"field": "email"}
|
||
|
||
|
||
class TestAppException:
|
||
"""测试业务异常类。"""
|
||
|
||
def test_app_exception_attributes(self):
|
||
"""验证 AppException 包含 code/message/data 属性。"""
|
||
exc = AppException(1002, "未授权")
|
||
|
||
assert exc.code == 1002
|
||
assert exc.message == "未授权"
|
||
assert exc.data is None
|
||
|
||
def test_app_exception_with_data(self):
|
||
"""验证 AppException 可附带数据。"""
|
||
exc = AppException(1001, "参数错误", data={"field": "id"})
|
||
|
||
assert exc.data == {"field": "id"}
|
||
|
||
def test_app_exception_is_exception(self):
|
||
"""验证 AppException 是 Exception 的子类。"""
|
||
exc = AppException(1001, "测试")
|
||
assert isinstance(exc, Exception)
|
||
|
||
def test_predefined_error_constants(self):
|
||
"""验证预定义错误常量。"""
|
||
from app.utils.response import (
|
||
ERR_PARAMS, ERR_UNAUTHORIZED, ERR_NOT_FOUND,
|
||
ERR_FORBIDDEN, ERR_INTERNAL,
|
||
)
|
||
|
||
assert ERR_PARAMS.code == 1001
|
||
assert ERR_UNAUTHORIZED.code == 1002
|
||
assert ERR_NOT_FOUND.code == 1003
|
||
assert ERR_FORBIDDEN.code == 1004
|
||
assert ERR_INTERNAL.code == 1005
|
||
|
||
|
||
class TestAPIRoutes:
|
||
"""测试 API 路由基础。"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_404_not_found(self, client, db_session):
|
||
"""验证访问不存在的路由返回 404。"""
|
||
response = await client.get("/nonexistent-route")
|
||
assert response.status_code == 404
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_api_prefix(self, client, db_session):
|
||
"""验证 API 路径前缀为 /api。"""
|
||
# /api/agents 是有效路由
|
||
response = await client.get("/agents")
|
||
assert response.status_code == 200
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_conversations_list_response_format(self, client, db_session, mock_redis):
|
||
"""验证会话列表 API 返回统一响应格式。"""
|
||
# 先登录坐席获取 token(/api/conversations 需要 get_current_agent 认证)
|
||
login_resp = await client.post(
|
||
"/agents/login",
|
||
json={"user_id": "basic_test_agent", "name": "基础测试坐席"},
|
||
)
|
||
token = login_resp.json()["data"]["token"]
|
||
|
||
response = await client.get(
|
||
"/conversations",
|
||
headers={"Authorization": f"Bearer {token}"},
|
||
)
|
||
|
||
data = response.json()
|
||
assert "code" in data
|
||
assert "data" in data
|
||
assert "message" in data
|
||
assert data["code"] == 0
|