首页 > 解决方案 > 如何在测试 ASP.NET Core 应用程序时使用 EF Core 使用 InMemory 数据库将数据播种到 DbContext?

问题描述

您好,我的应用程序中包含一些集成测试。在实例化测试类时,我正在使用以下类准备数据库:

internal static class DatabaseTestPreparation
{
    private const string TestDatabaseName = "TestDatabase";

    internal static IServiceCollection ConfigureTestDatabases(this IServiceCollection services) =>
        services
            .PrepareTestDatabaseContext<EventStoreContext>()
            .PrepareTestDatabaseContext<GrantContext>();

    private static IServiceCollection PrepareTestDatabaseContext<T>(this IServiceCollection services)
        where T : DbContext
    {
        var descriptor = services.SingleOrDefault(service =>
            service.ServiceType == typeof(DbContextOptions<T>));

        if (!(descriptor is null))
        {
            services
                .Remove(descriptor);
        }

        services
            .AddDbContext<T>(options =>
                options.UseInMemoryDatabase(TestDatabaseName))
            .Seed<T>();

        return services;
    }

    private static IServiceCollection Seed<T>(this IServiceCollection services) where T : DbContext
    {
        var serviceProvider = services.BuildServiceProvider();
        
        var dbContext = serviceProvider
            .GetService(typeof(T)) as T;

        dbContext
            ?.Database
            .EnsureCreated();

        return services;
    }
}

我的 DbContext 类中还包含一些种子逻辑。例如:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    CreateConstraints(modelBuilder);
    SeedInitialData(modelBuilder);
}

private static void CreateConstraints(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<PermissionEntity>()
        .HasIndex(permission => permission.Code)
        .IsUnique();
    
    modelBuilder.Entity<ApplicationEntity>()
        .HasIndex(app => app.Name)
        .IsUnique();
}

private static void SeedInitialData(ModelBuilder modelBuilder)
{
    var application = new ApplicationEntity
    {
        ...
    };
    
    modelBuilder.Entity<ApplicationEntity>()
        .HasData(application);

    var managerRole = new RoleEntity
    {
       ...
    };

    modelBuilder.Entity<RoleEntity>()
        .HasData(managerRole);

    var permission = new PermissionEntity
    {
        ...
    };

    modelBuilder.Entity<PermissionEntity>()
        .HasData(permission);

    var permissionRoleAssignment = new PermissionRoleAssignmentEntity
    {
        ...
    };

    modelBuilder.Entity<PermissionRoleAssignmentEntity>()
        .HasData(permissionRoleAssignment);

    var principal = new PrincipalEntity
    {
        ...
    };

    modelBuilder.Entity<PrincipalEntity>()
        .HasData(principal);

    var principalRoleAssignment = new PrincipalRoleAssignmentEntity
    {
        ...
    };

    modelBuilder.Entity<PrincipalRoleAssignmentEntity>()
        .HasData(principalRoleAssignment);
}

上面的这些方法肯定会正确执行,因为我在运行测试时已经用调试器检查了它。问题是,虽然我已经在 DbContext 类中编写了种子方法,但是当某些测试方法运行时,似乎在测试方法中使用的 DbContext 中没有数据。如何正确使用 EF Core InMemoryProvider 播种数据?我究竟做错了什么?

标签: c#asp.netasp.net-coreentity-framework-coreintegration-testing

解决方案


推荐阅读