Files
AI-Health/backend/tests/Health.Tests/entity_tests.cs
MingNian fade61ac21 feat: 二级页面色彩刷新 + 用药/通知/设备重构 + 后端健康档案/通知管线增强 + 大量测试
## 后端
- 健康档案: 新增手术状态字段 + EF 迁移; HealthArchiveService 新增查询方法
- 健康记录: HealthRecordService 新增批量/统计方法; 契约扩展
- 用药: 新增 MedicationScheduleStatus 枚举; MedicationService 排班逻辑调整
- 通知: EfUserNotificationPipeline 重构; 新增 EfReminderCatchUpService; 通知管线支持更多场景
- 用户: UserService 账号删除逻辑; 新增 local_account_file_cleanup; EfUserRepository 扩展
- AI: medication_agent_handler 微调; prompt_manager 优化; AiConversationService 上下文处理
- Endpoint: doctor/medication/exercise/health/notification/user 等多接口调整
- BackgroundService: health_record_reminder_service 重构, 提醒补漏逻辑
- 测试: 新增 account_deletion/doctor_endpoint/medication_schedule/medication_update/prompt_manager 测试

## 前端
- UI 系统: app_theme 大幅重构; app_colors/app_design_tokens/app_module_visuals 调整; 二级页面色彩刷新
- 主页: home_page 背景渐变 + 消息列表提取 _HomeMessages + 通知检查逻辑; chat_messages_view 全面重构
- 用药: medication_list/edit/checkin 三页重构, 新增 medication_ui_logic 抽取
- 通知: notification_prefs_page 重构, 新增 notification_prefs_logic; notification_center 优化
- 设备: device_management 重构, 新增 device_sync_ui_logic; device_scan 优化
- 趋势图: trend_page 大幅重构
- 登录: login_page 重构
- 个人资料: 新增 profile_edit_page; profile_page 优化
- 运动: 新增 exercise/ 目录 + care_plan_ui_logic
- 其他: remaining_pages/report_pages/health_drawer/admin/doctor 等多页面调整
- 组件: common_widgets/app_empty_state/app_error_state/app_future_view/app_toast/ai_content 优化
- Provider: chat_provider/consultation_provider/data_providers/auth_provider 调整
- AndroidManifest: 移除多余权限
- 测试: 新增 ai_content/care_plan/home_message/login_flow/medication_checkin/medication_ui/notification_prefs/profile_device/secondary_page/swipe_delete 等大量测试

## 文档
- 新增 ui-design-system.md 设计系统文档
- 新增 secondary-page-color-refresh 计划 + specs 目录
2026-07-15 23:22:52 +08:00

224 lines
9.3 KiB
C#

using Health.Domain.Entities;
using Health.Domain.Enums;
using Health.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;
namespace Health.Tests;
/// <summary>
/// 实体和数据库操作测试
/// </summary>
public class EntityTests
{
private AppDbContext CreateDbContext()
{
var options = new DbContextOptionsBuilder<AppDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
return new AppDbContext(options);
}
[Fact]
public async Task Create_HealthRecord_Should_Persist()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var record = new HealthRecord
{
Id = Guid.NewGuid(), UserId = user.Id, MetricType = HealthMetricType.BloodPressure,
Systolic = 128, Diastolic = 82, Unit = "mmHg",
Source = HealthRecordSource.AiEntry, RecordedAt = DateTime.UtcNow,
IsAbnormal = false,
};
db.HealthRecords.Add(record);
await db.SaveChangesAsync();
var saved = await db.HealthRecords.FirstOrDefaultAsync(r => r.UserId == user.Id);
Assert.NotNull(saved);
Assert.Equal(128, saved!.Systolic);
Assert.Equal(82, saved.Diastolic);
Assert.Equal(HealthMetricType.BloodPressure, saved.MetricType);
}
[Fact]
public async Task Abnormal_BloodPressure_Should_Flag_IsAbnormal()
{
var record = new HealthRecord
{
Systolic = 155, Diastolic = 95, MetricType = HealthMetricType.BloodPressure,
};
var isAbnormal = record.Systolic >= 140 || record.Diastolic >= 90
|| record.Systolic <= 89 || record.Diastolic <= 59;
Assert.True(isAbnormal);
}
[Fact]
public async Task Normal_BloodPressure_Should_Not_Flag()
{
var record = new HealthRecord
{
Systolic = 128, Diastolic = 82, MetricType = HealthMetricType.BloodPressure,
};
var isAbnormal = record.Systolic >= 140 || record.Diastolic >= 90
|| record.Systolic <= 89 || record.Diastolic <= 59;
Assert.False(isAbnormal);
}
[Fact]
public async Task Create_Medication_Should_Persist_With_TimeOfDay()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var med = new Medication
{
Id = Guid.NewGuid(), UserId = user.Id, Name = "阿司匹林", Dosage = "100mg",
Frequency = MedicationFrequency.Daily,
TimeOfDay = [new TimeOnly(8, 0)],
Source = MedicationSource.AiEntry, IsActive = true,
};
db.Medications.Add(med);
await db.SaveChangesAsync();
var saved = await db.Medications.FirstOrDefaultAsync(m => m.UserId == user.Id);
Assert.NotNull(saved);
Assert.Equal("阿司匹林", saved!.Name);
Assert.Equal("100mg", saved.Dosage);
Assert.Single(saved.TimeOfDay);
Assert.Equal(8, saved.TimeOfDay[0].Hour);
}
[Fact]
public async Task Medication_Confirm_Should_Create_Log()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
var med = new Medication { Id = Guid.NewGuid(), UserId = user.Id, Name = "阿托伐他汀", Dosage = "20mg", Frequency = MedicationFrequency.Daily, Source = MedicationSource.Prescription, IsActive = true };
db.Medications.Add(med);
await db.SaveChangesAsync();
// 打卡
var log = new MedicationLog
{
Id = Guid.NewGuid(), MedicationId = med.Id, UserId = user.Id,
Status = MedicationLogStatus.Taken, ScheduledTime = new TimeOnly(20, 0),
ConfirmedAt = DateTime.UtcNow,
};
db.MedicationLogs.Add(log);
await db.SaveChangesAsync();
var saved = await db.MedicationLogs.FirstOrDefaultAsync(l => l.MedicationId == med.Id);
Assert.NotNull(saved);
Assert.Equal(MedicationLogStatus.Taken, saved!.Status);
}
[Fact]
public async Task Conversation_With_Messages_Should_Work()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var conv = new Conversation { Id = Guid.NewGuid(), UserId = user.Id, AgentType = AgentType.Default, Title = "血压咨询", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Conversations.Add(conv);
var msg1 = new ConversationMessage { Id = Guid.NewGuid(), ConversationId = conv.Id, Role = MessageRole.User, Content = "血压 135/85", CreatedAt = DateTime.UtcNow };
var msg2 = new ConversationMessage { Id = Guid.NewGuid(), ConversationId = conv.Id, Role = MessageRole.Assistant, Content = "收到!已记录", CreatedAt = DateTime.UtcNow };
db.ConversationMessages.AddRange(msg1, msg2);
conv.MessageCount = 2;
await db.SaveChangesAsync();
var messages = await db.ConversationMessages.Where(m => m.ConversationId == conv.Id).OrderBy(m => m.CreatedAt).ToListAsync();
Assert.Equal(2, messages.Count);
Assert.Equal("血压 135/85", messages[0].Content);
Assert.Equal("收到!已记录", messages[1].Content);
}
[Fact]
public async Task DietRecord_With_FoodItems_Should_Work()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var diet = new DietRecord
{
Id = Guid.NewGuid(), UserId = user.Id, MealType = MealType.Lunch,
TotalCalories = 644, HealthScore = 3, RecordedAt = DateOnly.FromDateTime(DateTime.Now),
};
diet.FoodItems.Add(new DietFoodItem { Id = Guid.NewGuid(), Name = "米饭", Portion = "1碗", Calories = 174, SortOrder = 1 });
diet.FoodItems.Add(new DietFoodItem { Id = Guid.NewGuid(), Name = "红烧肉", Portion = "5块", Calories = 470, Warning = "脂肪偏高", SortOrder = 2 });
db.DietRecords.Add(diet);
await db.SaveChangesAsync();
var saved = await db.DietRecords.Include(d => d.FoodItems).FirstOrDefaultAsync(d => d.UserId == user.Id);
Assert.NotNull(saved);
Assert.Equal(2, saved!.FoodItems.Count);
Assert.Equal(644, saved.TotalCalories);
}
[Fact]
public async Task HealthArchive_Should_Store_All_Fields()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var archive = new HealthArchive
{
Id = Guid.NewGuid(), UserId = user.Id, Diagnosis = "冠心病",
SurgeryType = "PCI支架植入术", SurgeryDate = new DateOnly(2026, 3, 15),
Allergies = ["青霉素"],
DietRestrictions = ["低盐", "低脂"],
ChronicDiseases = ["高血压", "高血脂"],
FamilyHistory = "父亲冠心病",
SurgeryHistoryStatus = "有",
};
db.HealthArchives.Add(archive);
await db.SaveChangesAsync();
var saved = await db.HealthArchives.FirstOrDefaultAsync(a => a.UserId == user.Id);
Assert.NotNull(saved);
Assert.Equal("冠心病", saved!.Diagnosis);
Assert.Equal(2, saved.DietRestrictions.Count);
Assert.Contains("低盐", saved.DietRestrictions);
Assert.Equal("有", saved.SurgeryHistoryStatus);
}
[Fact]
public async Task ExercisePlan_Weekly_Tracking_Should_Work()
{
using var db = CreateDbContext();
var user = new User { Id = Guid.NewGuid(), Phone = "13800138000", CreatedAt = DateTime.UtcNow, UpdatedAt = DateTime.UtcNow };
db.Users.Add(user);
await db.SaveChangesAsync();
var monday = new DateOnly(2026, 6, 1);
var plan = new ExercisePlan { Id = Guid.NewGuid(), UserId = user.Id, StartDate = monday, EndDate = monday.AddDays(2), ReminderTime = new TimeOnly(19, 0) };
plan.Items.Add(new ExercisePlanItem { Id = Guid.NewGuid(), ScheduledDate = monday, ExerciseType = "散步", DurationMinutes = 30, IsCompleted = true, CompletedAt = DateTime.UtcNow });
plan.Items.Add(new ExercisePlanItem { Id = Guid.NewGuid(), ScheduledDate = monday.AddDays(1), ExerciseType = "慢跑", DurationMinutes = 20 });
plan.Items.Add(new ExercisePlanItem { Id = Guid.NewGuid(), ScheduledDate = monday.AddDays(2), IsRestDay = true });
db.ExercisePlans.Add(plan);
await db.SaveChangesAsync();
var saved = await db.ExercisePlans.Include(p => p.Items).FirstOrDefaultAsync(p => p.UserId == user.Id);
Assert.NotNull(saved);
Assert.Equal(3, saved!.Items.Count);
var completed = saved.Items.Count(i => i.IsCompleted);
Assert.Equal(1, completed);
}
}