主要更新: - 更新代理商端文档,明确项目由品牌方分配流程 - 新增Brief配置详情页(已配置)设计稿 - 完善工作台紧急待办中品牌新任务功能 - 整理Pencil设计文件中代理商端页面顺序 - 新增后端FastAPI框架及核心API - 新增前端Next.js页面和组件库 - 添加.gitignore排除构建和缓存文件 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
159 lines
5.4 KiB
Python
159 lines
5.4 KiB
Python
"""
|
||
健康检查 API 测试
|
||
测试覆盖: /health, /health/ready, /health/live
|
||
使用依赖注入 mock 健康检查器
|
||
"""
|
||
import pytest
|
||
from httpx import AsyncClient
|
||
|
||
from app.config import Settings
|
||
|
||
|
||
class TestHealthCheck:
|
||
"""健康检查端点测试"""
|
||
|
||
# ==================== /health 测试 ====================
|
||
@pytest.mark.asyncio
|
||
async def test_health_check_returns_200(self, client: AsyncClient):
|
||
"""健康检查返回 200 状态码"""
|
||
response = await client.get("/api/v1/health")
|
||
assert response.status_code == 200
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_health_check_response_structure(self, client: AsyncClient):
|
||
"""健康检查返回正确的响应结构"""
|
||
response = await client.get("/api/v1/health")
|
||
data = response.json()
|
||
|
||
assert "status" in data
|
||
assert "service" in data
|
||
assert "version" in data
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_health_check_uses_settings(
|
||
self, client: AsyncClient, app_settings: Settings
|
||
):
|
||
"""健康检查使用 settings 中的配置"""
|
||
response = await client.get("/api/v1/health")
|
||
data = response.json()
|
||
|
||
assert data["status"] == "healthy"
|
||
# 使用 settings 中的值,而非硬编码
|
||
assert data["service"] == app_settings.APP_NAME
|
||
assert data["version"] == app_settings.APP_VERSION
|
||
|
||
# ==================== /health/ready 测试 ====================
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_returns_200(
|
||
self, client: AsyncClient, mock_health_checker
|
||
):
|
||
"""就绪检查返回 200 状态码"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
assert response.status_code == 200
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_ready_when_all_healthy(
|
||
self, client: AsyncClient, mock_health_checker
|
||
):
|
||
"""所有依赖健康时返回 ready=true"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
data = response.json()
|
||
|
||
assert data["ready"] is True
|
||
assert data["checks"]["database"] is True
|
||
assert data["checks"]["redis"] is True
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_not_ready_when_db_unhealthy(
|
||
self, client: AsyncClient, mock_unhealthy_db_checker
|
||
):
|
||
"""数据库不健康时返回 ready=false"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
data = response.json()
|
||
|
||
assert data["ready"] is False
|
||
assert data["checks"]["database"] is False
|
||
assert data["checks"]["redis"] is True
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_not_ready_when_redis_unhealthy(
|
||
self, client: AsyncClient, mock_unhealthy_redis_checker
|
||
):
|
||
"""Redis 不健康时返回 ready=false"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
data = response.json()
|
||
|
||
assert data["ready"] is False
|
||
assert data["checks"]["database"] is True
|
||
assert data["checks"]["redis"] is False
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_not_ready_when_all_unhealthy(
|
||
self, client: AsyncClient, mock_all_unhealthy_checker
|
||
):
|
||
"""所有依赖不健康时返回 ready=false"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
data = response.json()
|
||
|
||
assert data["ready"] is False
|
||
assert data["checks"]["database"] is False
|
||
assert data["checks"]["redis"] is False
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_readiness_check_returns_checks_detail(
|
||
self, client: AsyncClient, mock_health_checker
|
||
):
|
||
"""就绪检查返回详细的检查结果"""
|
||
response = await client.get("/api/v1/health/ready")
|
||
data = response.json()
|
||
|
||
assert "checks" in data
|
||
assert "database" in data["checks"]
|
||
assert "redis" in data["checks"]
|
||
|
||
# ==================== /health/live 测试 ====================
|
||
@pytest.mark.asyncio
|
||
async def test_liveness_check_returns_200(self, client: AsyncClient):
|
||
"""存活检查返回 200 状态码"""
|
||
response = await client.get("/api/v1/health/live")
|
||
assert response.status_code == 200
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_liveness_check_always_alive(self, client: AsyncClient):
|
||
"""存活检查始终返回 alive=true(只检查进程存活)"""
|
||
response = await client.get("/api/v1/health/live")
|
||
data = response.json()
|
||
|
||
# liveness 不依赖外部服务,只要进程活着就返回 true
|
||
assert data["alive"] is True
|
||
|
||
|
||
class TestRootEndpoint:
|
||
"""根路径测试"""
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_root_returns_200(self, client: AsyncClient):
|
||
"""根路径返回 200 状态码"""
|
||
response = await client.get("/")
|
||
assert response.status_code == 200
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_root_response_structure(self, client: AsyncClient):
|
||
"""根路径返回正确的响应结构"""
|
||
response = await client.get("/")
|
||
data = response.json()
|
||
|
||
assert "message" in data
|
||
assert "version" in data
|
||
|
||
@pytest.mark.asyncio
|
||
async def test_root_uses_settings(
|
||
self, client: AsyncClient, app_settings: Settings
|
||
):
|
||
"""根路径使用 settings 中的应用名称"""
|
||
response = await client.get("/")
|
||
data = response.json()
|
||
|
||
# 验证响应中包含 settings.APP_NAME
|
||
assert app_settings.APP_NAME in data["message"]
|