Files
DDUp/tests/test_web.py

285 lines
8.0 KiB
Python
Raw Normal View History

2026-01-22 12:57:26 +08:00
"""Web API 测试"""
from datetime import date, timedelta
import pytest
from fastapi.testclient import TestClient
from src.vitals.core import database as db
from src.vitals.core.models import Exercise, Meal, Sleep, Weight, UserConfig
@pytest.fixture
def client():
"""创建测试客户端"""
from src.vitals.web.app import app
return TestClient(app)
@pytest.fixture
def populated_db():
"""填充测试数据"""
today = date.today()
# 用户配置
config = UserConfig(
age=28, gender="male", height=175.0, weight=72.0,
activity_level="moderate", goal="maintain",
)
db.save_config(config)
# 今日数据
db.add_exercise(Exercise(
date=today, type="跑步", duration=30, calories=240, distance=5.0,
))
db.add_meal(Meal(
date=today, meal_type="午餐",
description="米饭+鸡肉", calories=500,
))
db.add_meal(Meal(
date=today, meal_type="早餐",
description="燕麦+鸡蛋", calories=350,
))
db.add_sleep(Sleep(
date=today, duration=7.5, quality=4,
))
db.add_weight(Weight(
date=today, weight_kg=72.5, body_fat_pct=18.5,
))
return today
class TestRootEndpoint:
"""根路径测试"""
def test_root_returns_html(self, client):
"""测试返回 HTML"""
response = client.get("/")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
def test_root_contains_dashboard(self, client):
"""测试包含仪表盘内容"""
response = client.get("/")
assert "Vitals" in response.text
assert "健康管理" in response.text
class TestConfigEndpoint:
"""配置接口测试"""
def test_get_config(self, client, populated_db):
"""测试获取配置"""
response = client.get("/api/config")
assert response.status_code == 200
data = response.json()
assert data["age"] == 28
assert data["gender"] == "male"
assert data["bmr"] is not None
assert data["tdee"] is not None
def test_get_config_empty(self, client):
"""测试空配置"""
response = client.get("/api/config")
assert response.status_code == 200
data = response.json()
assert data["activity_level"] == "moderate"
class TestTodayEndpoint:
"""今日概览接口测试"""
def test_get_today(self, client, populated_db):
"""测试获取今日数据"""
response = client.get("/api/today")
assert response.status_code == 200
data = response.json()
assert data["date"] == date.today().isoformat()
assert data["calories_intake"] > 0
assert data["exercise_count"] == 1
def test_today_has_meals(self, client, populated_db):
"""测试包含饮食"""
response = client.get("/api/today")
data = response.json()
assert len(data["meals"]) == 2
assert data["meals"][0]["meal_type"] in ["午餐", "早餐"]
def test_today_has_exercises(self, client, populated_db):
"""测试包含运动"""
response = client.get("/api/today")
data = response.json()
assert len(data["exercises"]) == 1
assert data["exercises"][0]["type"] == "跑步"
def test_today_empty(self, client):
"""测试空数据"""
response = client.get("/api/today")
assert response.status_code == 200
data = response.json()
assert data["calories_intake"] == 0
assert data["exercise_count"] == 0
class TestWeekEndpoint:
"""本周汇总接口测试"""
def test_get_week(self, client, populated_db):
"""测试获取本周数据"""
response = client.get("/api/week")
assert response.status_code == 200
data = response.json()
assert "start_date" in data
assert "end_date" in data
assert "daily_stats" in data
def test_week_has_daily_stats(self, client, populated_db):
"""测试包含每日统计"""
response = client.get("/api/week")
data = response.json()
assert len(data["daily_stats"]) == 7
for stat in data["daily_stats"]:
assert "date" in stat
assert "weekday" in stat
def test_week_date_range(self, client, populated_db):
"""测试日期范围"""
response = client.get("/api/week")
data = response.json()
start = date.fromisoformat(data["start_date"])
end = date.fromisoformat(data["end_date"])
assert (end - start).days == 6
class TestExercisesEndpoint:
"""运动记录接口测试"""
def test_get_exercises(self, client, populated_db):
"""测试获取运动记录"""
response = client.get("/api/exercises")
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
def test_exercises_with_days_param(self, client, populated_db):
"""测试天数参数"""
response = client.get("/api/exercises?days=7")
assert response.status_code == 200
def test_exercises_invalid_days(self, client):
"""测试无效天数"""
response = client.get("/api/exercises?days=0")
assert response.status_code == 422 # Validation error
def test_exercises_empty(self, client):
"""测试空数据"""
response = client.get("/api/exercises")
assert response.status_code == 200
assert response.json() == []
class TestMealsEndpoint:
"""饮食记录接口测试"""
def test_get_meals(self, client, populated_db):
"""测试获取饮食记录"""
response = client.get("/api/meals")
assert response.status_code == 200
data = response.json()
assert len(data) >= 2
def test_meals_structure(self, client, populated_db):
"""测试数据结构"""
response = client.get("/api/meals")
data = response.json()
meal = data[0]
assert "id" in meal
assert "date" in meal
assert "meal_type" in meal
assert "description" in meal
assert "calories" in meal
class TestSleepEndpoint:
"""睡眠记录接口测试"""
def test_get_sleep(self, client, populated_db):
"""测试获取睡眠记录"""
response = client.get("/api/sleep")
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
def test_sleep_structure(self, client, populated_db):
"""测试数据结构"""
response = client.get("/api/sleep")
data = response.json()
record = data[0]
assert "duration" in record
assert "quality" in record
class TestWeightEndpoint:
"""体重记录接口测试"""
def test_get_weight(self, client, populated_db):
"""测试获取体重记录"""
response = client.get("/api/weight")
assert response.status_code == 200
data = response.json()
assert len(data) >= 1
def test_weight_default_days(self, client, populated_db):
"""测试默认天数"""
response = client.get("/api/weight")
assert response.status_code == 200
def test_weight_structure(self, client, populated_db):
"""测试数据结构"""
response = client.get("/api/weight")
data = response.json()
record = data[0]
assert "weight_kg" in record
assert record["weight_kg"] == 72.5
class TestCORS:
"""CORS 测试"""
def test_cors_headers(self, client):
"""测试 CORS 头"""
response = client.options("/api/config")
# FastAPI with CORSMiddleware should handle OPTIONS
assert response.status_code in [200, 405]
class TestErrorHandling:
"""错误处理测试"""
def test_not_found(self, client):
"""测试 404"""
response = client.get("/api/nonexistent")
assert response.status_code == 404
def test_invalid_query_params(self, client):
"""测试无效参数"""
response = client.get("/api/exercises?days=abc")
assert response.status_code == 422