第一版
This commit is contained in:
267
tests/test_models.py
Normal file
267
tests/test_models.py
Normal file
@@ -0,0 +1,267 @@
|
||||
"""数据模型测试"""
|
||||
|
||||
from datetime import date, time
|
||||
|
||||
import pytest
|
||||
|
||||
from src.vitals.core.models import (
|
||||
Exercise,
|
||||
Meal,
|
||||
Sleep,
|
||||
Weight,
|
||||
UserConfig,
|
||||
MealType,
|
||||
ExerciseType,
|
||||
ActivityLevel,
|
||||
Goal,
|
||||
User,
|
||||
DataClearRequest,
|
||||
)
|
||||
|
||||
|
||||
class TestExercise:
|
||||
"""运动记录模型测试"""
|
||||
|
||||
def test_create_exercise(self):
|
||||
"""测试创建运动记录"""
|
||||
exercise = Exercise(
|
||||
date=date(2026, 1, 18),
|
||||
type="跑步",
|
||||
duration=30,
|
||||
calories=240,
|
||||
)
|
||||
assert exercise.type == "跑步"
|
||||
assert exercise.duration == 30
|
||||
assert exercise.calories == 240
|
||||
|
||||
def test_exercise_to_dict(self, sample_exercise):
|
||||
"""测试转换为字典"""
|
||||
data = sample_exercise.to_dict()
|
||||
assert data["type"] == "跑步"
|
||||
assert data["duration"] == 30
|
||||
assert data["distance"] == 5.0
|
||||
assert data["date"] == "2026-01-18"
|
||||
|
||||
def test_exercise_default_values(self):
|
||||
"""测试默认值"""
|
||||
exercise = Exercise()
|
||||
assert exercise.duration == 0
|
||||
assert exercise.calories == 0
|
||||
assert exercise.source == "手动"
|
||||
|
||||
|
||||
class TestMeal:
|
||||
"""饮食记录模型测试"""
|
||||
|
||||
def test_create_meal(self):
|
||||
"""测试创建饮食记录"""
|
||||
meal = Meal(
|
||||
meal_type="早餐",
|
||||
description="燕麦+鸡蛋",
|
||||
calories=350,
|
||||
)
|
||||
assert meal.meal_type == "早餐"
|
||||
assert meal.calories == 350
|
||||
|
||||
def test_meal_to_dict(self, sample_meal):
|
||||
"""测试转换为字典"""
|
||||
data = sample_meal.to_dict()
|
||||
assert data["meal_type"] == "午餐"
|
||||
assert data["calories"] == 650
|
||||
assert data["protein"] == 25.0
|
||||
|
||||
def test_meal_with_food_items(self):
|
||||
"""测试带食物条目的饮食记录"""
|
||||
meal = Meal(
|
||||
meal_type="午餐",
|
||||
description="测试",
|
||||
food_items=[{"name": "米饭", "calories": 200}],
|
||||
)
|
||||
data = meal.to_dict()
|
||||
assert "米饭" in data["food_items"]
|
||||
|
||||
|
||||
class TestSleep:
|
||||
"""睡眠记录模型测试"""
|
||||
|
||||
def test_create_sleep(self):
|
||||
"""测试创建睡眠记录"""
|
||||
sleep = Sleep(
|
||||
bedtime=time(23, 0),
|
||||
wake_time=time(7, 0),
|
||||
duration=8.0,
|
||||
quality=4,
|
||||
)
|
||||
assert sleep.duration == 8.0
|
||||
assert sleep.quality == 4
|
||||
|
||||
def test_sleep_to_dict(self, sample_sleep):
|
||||
"""测试转换为字典"""
|
||||
data = sample_sleep.to_dict()
|
||||
assert data["duration"] == 7.5
|
||||
assert data["quality"] == 4
|
||||
assert data["bedtime"] == "23:30:00"
|
||||
|
||||
|
||||
class TestWeight:
|
||||
"""体重记录模型测试"""
|
||||
|
||||
def test_create_weight(self):
|
||||
"""测试创建体重记录"""
|
||||
weight = Weight(weight_kg=72.5)
|
||||
assert weight.weight_kg == 72.5
|
||||
|
||||
def test_weight_to_dict(self, sample_weight):
|
||||
"""测试转换为字典"""
|
||||
data = sample_weight.to_dict()
|
||||
assert data["weight_kg"] == 72.5
|
||||
assert data["body_fat_pct"] == 18.5
|
||||
|
||||
|
||||
class TestUserConfig:
|
||||
"""用户配置模型测试"""
|
||||
|
||||
def test_bmr_calculation_male(self):
|
||||
"""测试男性 BMR 计算"""
|
||||
config = UserConfig(
|
||||
age=28,
|
||||
gender="male",
|
||||
height=175.0,
|
||||
weight=72.0,
|
||||
)
|
||||
# Mifflin-St Jeor: 10 * 72 + 6.25 * 175 - 5 * 28 + 5 = 1678
|
||||
assert config.bmr == 1678
|
||||
|
||||
def test_bmr_calculation_female(self):
|
||||
"""测试女性 BMR 计算"""
|
||||
config = UserConfig(
|
||||
age=25,
|
||||
gender="female",
|
||||
height=165.0,
|
||||
weight=55.0,
|
||||
)
|
||||
# Mifflin-St Jeor: 10 * 55 + 6.25 * 165 - 5 * 25 - 161 = 1295
|
||||
assert config.bmr == 1295
|
||||
|
||||
def test_bmr_none_when_incomplete(self):
|
||||
"""测试不完整时 BMR 为 None"""
|
||||
config = UserConfig(age=28)
|
||||
assert config.bmr is None
|
||||
|
||||
def test_tdee_calculation(self, sample_config):
|
||||
"""测试 TDEE 计算"""
|
||||
# BMR * 1.55 (moderate)
|
||||
expected_tdee = int(sample_config.bmr * 1.55)
|
||||
assert sample_config.tdee == expected_tdee
|
||||
|
||||
def test_tdee_different_activity_levels(self):
|
||||
"""测试不同活动水平的 TDEE"""
|
||||
base_config = {
|
||||
"age": 30,
|
||||
"gender": "male",
|
||||
"height": 175.0,
|
||||
"weight": 70.0,
|
||||
}
|
||||
|
||||
sedentary = UserConfig(**base_config, activity_level="sedentary")
|
||||
active = UserConfig(**base_config, activity_level="active")
|
||||
|
||||
assert sedentary.tdee < active.tdee
|
||||
|
||||
def test_config_to_dict(self, sample_config):
|
||||
"""测试转换为字典"""
|
||||
data = sample_config.to_dict()
|
||||
assert data["age"] == 28
|
||||
assert data["gender"] == "male"
|
||||
assert data["bmr"] is not None
|
||||
assert data["tdee"] is not None
|
||||
|
||||
|
||||
class TestEnums:
|
||||
"""枚举类型测试"""
|
||||
|
||||
def test_meal_type_values(self):
|
||||
"""测试餐次类型"""
|
||||
assert MealType.BREAKFAST.value == "早餐"
|
||||
assert MealType.LUNCH.value == "午餐"
|
||||
assert MealType.DINNER.value == "晚餐"
|
||||
assert MealType.SNACK.value == "加餐"
|
||||
|
||||
def test_exercise_type_values(self):
|
||||
"""测试运动类型"""
|
||||
assert ExerciseType.RUNNING.value == "跑步"
|
||||
assert ExerciseType.SWIMMING.value == "游泳"
|
||||
|
||||
def test_activity_level_values(self):
|
||||
"""测试活动水平"""
|
||||
assert ActivityLevel.SEDENTARY.value == "sedentary"
|
||||
assert ActivityLevel.MODERATE.value == "moderate"
|
||||
|
||||
def test_goal_values(self):
|
||||
"""测试目标"""
|
||||
assert Goal.LOSE.value == "lose"
|
||||
assert Goal.MAINTAIN.value == "maintain"
|
||||
assert Goal.GAIN.value == "gain"
|
||||
|
||||
|
||||
class TestUser:
|
||||
"""用户模型测试"""
|
||||
|
||||
def test_user_creation(self):
|
||||
"""测试创建用户"""
|
||||
from datetime import datetime
|
||||
user = User(
|
||||
name="小明",
|
||||
created_at=datetime.now(),
|
||||
)
|
||||
assert user.name == "小明"
|
||||
assert user.is_active == False
|
||||
assert user.id is None
|
||||
|
||||
def test_user_to_dict(self):
|
||||
"""测试用户转换为字典"""
|
||||
from datetime import datetime
|
||||
user = User(
|
||||
id=1,
|
||||
name="小红",
|
||||
created_at=datetime(2026, 1, 19, 10, 0, 0),
|
||||
is_active=True,
|
||||
)
|
||||
d = user.to_dict()
|
||||
assert d["id"] == 1
|
||||
assert d["name"] == "小红"
|
||||
assert d["is_active"] == True
|
||||
assert "created_at" in d
|
||||
|
||||
|
||||
class TestDataClearRequest:
|
||||
"""数据清除请求模型测试"""
|
||||
|
||||
def test_clear_by_range(self):
|
||||
"""测试按时间范围清除"""
|
||||
req = DataClearRequest(
|
||||
user_id=1,
|
||||
mode="range",
|
||||
date_from=date(2026, 1, 1),
|
||||
date_to=date(2026, 1, 15),
|
||||
)
|
||||
assert req.mode == "range"
|
||||
assert req.date_from == date(2026, 1, 1)
|
||||
|
||||
def test_clear_by_type(self):
|
||||
"""测试按类型清除"""
|
||||
req = DataClearRequest(
|
||||
user_id=1,
|
||||
mode="type",
|
||||
data_types=["exercise", "meal"],
|
||||
)
|
||||
assert req.mode == "type"
|
||||
assert "exercise" in req.data_types
|
||||
|
||||
def test_clear_all(self):
|
||||
"""测试清除全部"""
|
||||
req = DataClearRequest(
|
||||
user_id=1,
|
||||
mode="all",
|
||||
)
|
||||
assert req.mode == "all"
|
||||
Reference in New Issue
Block a user