Files
DDUp/tests/test_report.py
2026-01-22 12:57:26 +08:00

299 lines
8.7 KiB
Python

"""报告生成测试"""
from datetime import date, time, timedelta
from pathlib import Path
import pytest
from src.vitals.core import database as db
from src.vitals.core.models import Exercise, Meal, Sleep, Weight, UserConfig
from src.vitals.core.report import (
generate_weekly_report,
generate_monthly_report,
render_weekly_report_terminal,
render_weekly_report_markdown,
render_weekly_report_html,
export_report,
)
@pytest.fixture
def populated_db():
"""填充测试数据"""
today = date.today()
# 添加用户配置
config = UserConfig(
age=28, gender="male", height=175.0, weight=72.0,
activity_level="moderate", goal="lose",
)
db.save_config(config)
# 添加本周数据
for i in range(7):
day = today - timedelta(days=today.weekday()) + timedelta(days=i)
# 运动
if i % 2 == 0:
db.add_exercise(Exercise(
date=day, type="跑步", duration=30, calories=240,
))
# 饮食
db.add_meal(Meal(
date=day, meal_type="午餐",
description="米饭+鸡肉", calories=500,
))
# 睡眠
db.add_sleep(Sleep(
date=day, duration=7.0 + i * 0.1, quality=3 + (i % 3),
))
# 体重
db.add_weight(Weight(
date=day, weight_kg=72.0 - i * 0.1,
))
return today
class TestGenerateWeeklyReport:
"""周报生成测试"""
def test_generate_report(self, populated_db):
"""测试生成周报"""
report = generate_weekly_report()
assert report is not None
assert report.exercise_count > 0
assert report.exercise_duration > 0
def test_report_date_range(self, populated_db):
"""测试日期范围"""
report = generate_weekly_report()
# 本周应该是周一到周日
assert report.end_date - report.start_date == timedelta(days=6)
assert report.start_date.weekday() == 0 # 周一
def test_report_exercise_stats(self, populated_db):
"""测试运动统计"""
report = generate_weekly_report()
assert report.exercise_count > 0
assert report.exercise_duration > 0
assert report.exercise_calories > 0
assert "跑步" in report.exercise_types
def test_report_sleep_stats(self, populated_db):
"""测试睡眠统计"""
report = generate_weekly_report()
assert report.avg_sleep_duration > 0
assert 1 <= report.avg_sleep_quality <= 5
def test_report_weight_stats(self, populated_db):
"""测试体重统计"""
report = generate_weekly_report()
assert report.weight_start is not None
assert report.weight_end is not None
assert report.weight_change is not None
def test_report_daily_stats(self, populated_db):
"""测试每日统计"""
report = generate_weekly_report()
assert len(report.daily_stats) == 7
for stat in report.daily_stats:
assert stat.weekday in ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
def test_report_with_custom_date(self, populated_db):
"""测试指定日期"""
report = generate_weekly_report(date(2026, 1, 15))
# 2026-01-15 是周四, 那周的周一是 01-12
assert report.start_date == date(2026, 1, 12)
assert report.end_date == date(2026, 1, 18)
class TestGenerateMonthlyReport:
"""月报生成测试"""
def test_generate_report(self, populated_db):
"""测试生成月报"""
report = generate_monthly_report()
assert report is not None
assert report.year > 0
assert 1 <= report.month <= 12
def test_report_date_range(self, populated_db):
"""测试日期范围"""
report = generate_monthly_report(2026, 1)
assert report.start_date == date(2026, 1, 1)
assert report.end_date == date(2026, 1, 31)
def test_report_exercise_stats(self, populated_db):
"""测试运动统计"""
report = generate_monthly_report()
assert report.exercise_count >= 0
assert report.exercise_days >= 0
def test_report_weekly_summaries(self, populated_db):
"""测试周汇总"""
report = generate_monthly_report()
assert len(report.weekly_summaries) > 0
for week in report.weekly_summaries:
assert "week" in week
assert "exercise_duration" in week
def test_report_with_custom_month(self):
"""测试指定月份"""
report = generate_monthly_report(2025, 6)
assert report.year == 2025
assert report.month == 6
class TestRenderWeeklyReportTerminal:
"""终端渲染测试"""
def test_render_contains_sections(self, populated_db):
"""测试包含各部分"""
report = generate_weekly_report()
output = render_weekly_report_terminal(report)
assert "运动" in output
assert "睡眠" in output
assert "饮食" in output
assert "体重" in output
assert "每日明细" in output
def test_render_contains_stats(self, populated_db):
"""测试包含统计数据"""
report = generate_weekly_report()
output = render_weekly_report_terminal(report)
assert "分钟" in output
assert "" in output
class TestRenderWeeklyReportMarkdown:
"""Markdown 渲染测试"""
def test_render_is_valid_markdown(self, populated_db):
"""测试是有效的 Markdown"""
report = generate_weekly_report()
output = render_weekly_report_markdown(report)
assert output.startswith("# ")
assert "## " in output
assert "| " in output # 表格
def test_render_contains_sections(self, populated_db):
"""测试包含各部分"""
report = generate_weekly_report()
output = render_weekly_report_markdown(report)
assert "## 运动" in output
assert "## 睡眠" in output
assert "## 饮食" in output
assert "## 体重" in output
class TestRenderWeeklyReportHtml:
"""HTML 渲染测试"""
def test_render_is_valid_html(self, populated_db):
"""测试是有效的 HTML"""
report = generate_weekly_report()
output = render_weekly_report_html(report)
assert "<!DOCTYPE html>" in output
assert "<html" in output
assert "</html>" in output
def test_render_contains_styles(self, populated_db):
"""测试包含样式"""
report = generate_weekly_report()
output = render_weekly_report_html(report)
assert "<style>" in output
assert "</style>" in output
def test_render_contains_data(self, populated_db):
"""测试包含数据"""
report = generate_weekly_report()
output = render_weekly_report_html(report)
assert "运动" in output
assert "睡眠" in output
class TestExportReport:
"""报告导出测试"""
def test_export_markdown(self, populated_db, tmp_path):
"""测试导出 Markdown"""
report = generate_weekly_report()
output_path = tmp_path / "report.md"
result = export_report(report, output_path)
assert result is True
assert output_path.exists()
content = output_path.read_text()
assert "# " in content
def test_export_html(self, populated_db, tmp_path):
"""测试导出 HTML"""
report = generate_weekly_report()
output_path = tmp_path / "report.html"
result = export_report(report, output_path)
assert result is True
assert output_path.exists()
content = output_path.read_text()
assert "<!DOCTYPE html>" in content
def test_export_unsupported_format(self, populated_db, tmp_path):
"""测试不支持的格式"""
report = generate_weekly_report()
output_path = tmp_path / "report.xyz"
result = export_report(report, output_path)
assert result is False
class TestEmptyData:
"""空数据测试"""
def test_weekly_report_empty(self):
"""测试空数据周报"""
report = generate_weekly_report()
assert report.exercise_count == 0
assert report.avg_sleep_duration == 0
assert report.weight_start is None
def test_monthly_report_empty(self):
"""测试空数据月报"""
report = generate_monthly_report()
assert report.exercise_count == 0
assert report.avg_sleep_duration == 0
def test_render_empty_report(self):
"""测试渲染空报告"""
report = generate_weekly_report()
output = render_weekly_report_terminal(report)
assert "暂无记录" in output or "0" in output