How to seed data to DbContext using EF Core using InMemory Database while testing ASP.NET Core application?

Viewed 1534

Hello i have some integration tests included to my application. While instantiating a test class i am preparing the databases using following class:

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;
    }
}

I also have some seed logic contained in my DbContext classes. For example:

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);
}

These methods above executes correctly for sure because i've checked it with the the debugger, while running my tests. The problem is, although i've written seed method in DbContext the class, when some test methods are running no data seems to be in DbContext used in test methods. How to seed data with EF Core InMemoryProvider correctly? What am i doing wrong?

0 Answers
Related