using Jiaowu.Api.Domain.Academic; using Jiaowu.Api.Infrastructure.Caching; using Jiaowu.Api.Infrastructure.Persistence; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging.Abstractions; namespace Jiaowu.Api.Tests; public sealed class DemoDataSeederTests { [Fact] public async Task SeedAsync_populates_an_empty_business_database() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); await using var db = await CreateDatabaseAsync(connection); await SeedCourseCategoriesAsync(db); var seeder = new DemoDataSeeder( db, NoOpAppCache.Instance, NullLogger.Instance); await seeder.SeedAsync(); Assert.Equal(1, await db.Campuses.CountAsync()); Assert.Equal(16, await db.Colleges.CountAsync()); Assert.Equal(52, await db.Majors.CountAsync()); Assert.Equal(104, await db.AdministrativeClasses.CountAsync()); Assert.Equal(128, await db.Teachers.CountAsync()); Assert.Equal(3640, await db.Students.CountAsync()); Assert.Equal(148, await db.Courses.CountAsync()); Assert.Equal(736, await db.TeacherCourseApplications.CountAsync()); Assert.Equal(1, await db.AcademicTerms.CountAsync(x => x.IsCurrent)); Assert.Equal(30, await db.Classrooms.CountAsync()); } [Fact] public async Task SeedAsync_rejects_a_database_with_business_data() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); await using var db = await CreateDatabaseAsync(connection); await SeedCourseCategoriesAsync(db); db.Campuses.Add(new Campus { Code = "EXISTING", Name = "现有校区" }); await db.SaveChangesAsync(); var seeder = new DemoDataSeeder( db, NoOpAppCache.Instance, NullLogger.Instance); var exception = await Assert.ThrowsAsync( () => seeder.SeedAsync()); Assert.Contains("只允许写入没有业务数据的新数据库", exception.Message); Assert.Contains("校区", exception.Message); Assert.Equal(1, await db.Campuses.CountAsync()); } [Fact] public async Task SeedAsync_rolls_back_all_demo_rows_when_insertion_fails() { await using var connection = new SqliteConnection("Data Source=:memory:"); await connection.OpenAsync(); await using var db = await CreateDatabaseAsync(connection); await SeedCourseCategoriesAsync(db); var practiceCategory = await db.CourseCategories .SingleAsync(x => x.Code == "PRACTICE"); db.CourseCategories.Remove(practiceCategory); await db.SaveChangesAsync(); var seeder = new DemoDataSeeder( db, NoOpAppCache.Instance, NullLogger.Instance); await Assert.ThrowsAsync(() => seeder.SeedAsync()); db.ChangeTracker.Clear(); Assert.Equal(0, await db.Campuses.CountAsync()); Assert.Equal(0, await db.Colleges.CountAsync()); Assert.Equal(0, await db.Students.CountAsync()); Assert.Equal(0, await db.Courses.CountAsync()); Assert.Equal(0, await db.AcademicTerms.CountAsync()); Assert.Equal(0, await db.Classrooms.CountAsync()); } private static async Task CreateDatabaseAsync( SqliteConnection connection) { var options = new DbContextOptionsBuilder() .UseSqlite(connection) .Options; var db = new AppDbContext(options); await db.Database.EnsureCreatedAsync(); return db; } private static async Task SeedCourseCategoriesAsync(AppDbContext db) { db.CourseCategories.AddRange( CreateCategory("BASIC", "基础课程", 10), CreateCategory("MORAL", "德育课程", 20), CreateCategory("AESTHETIC", "美育课程", 30), CreateCategory("LABOR", "劳动教育", 40), CreateCategory("INNOVATION", "创新创业", 50), CreateCategory("ENGLISH", "大学英语", 60), CreateCategory("SPORTS", "大学体育", 70), CreateCategory("MILITARY", "国防教育", 80), CreateCategory("MAJOR", "专业教育", 90), CreateCategory("PRACTICE", "实践教学", 100)); await db.SaveChangesAsync(); } private static CourseCategory CreateCategory( string code, string name, int sortOrder) => new() { Code = code, Name = name, SortOrder = sortOrder }; }