替换WebApplicationFactory中的DbContext进行单元测试

xak*_*akz 5 unit-testing entity-framework-core .net-core asp.net-core

我需要替换 WebApplicationFactory 中的上下文。我有 MyDbContext,我想用 SQLite 上下文替换它以进行测试。

更换部件工作正常

.ConfigureServices(services =>
  {
    // Remove the app's ApplicationDbContext registration.
    var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>));

    if (descriptor != null)
    {
      services.Remove(descriptor);
    }
    
    services.AddDbContext<MyDbContext>(builder =>
    {
      builder.UseSqlite(CreateInMemoryDatabase());
    });
  });
Run Code Online (Sandbox Code Playgroud)

但因为我在测试中从 Npgsql 迁移到 SQLite,所以我需要覆盖 OnModelCreating 中的一些默认值。我创建了一个新的数据库上下文类

public class MySqlLiteDbContext: MyDbContext
    {
        public MySqlLiteDbContext(DbContextOptions<MyDbContext> options) : base(options)
        {
        }

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

            modelBuilder.Entity<Record>()
                .Property(b => b.DateCreated)
                .HasDefaultValueSql("(datetime('now'))");

            ...
        }
    }
Run Code Online (Sandbox Code Playgroud)

有没有什么方法可以注入MySqlLiteDbContext而不是MyDbContext强制 EnsureCreated 用于OnModelCreatingSQLite?提取是IMyDbContext一个选项吗?我还能做什么来解决这个问题?

xak*_*akz 4

好吧,看来我设法这样解决了

  1. 添加非泛型 DBContext 构造函数重写,使其protected
    public class MyDbContext: DbContext {        
        public MyDbContext(DbContextOptions < MyDbContext > options): base(options) {}
        // new
        protected MyDbContext(DbContextOptions options): base(options) {}
        
        // rest context stuff...
    }
Run Code Online (Sandbox Code Playgroud)
  1. WebApplicationFactory删除on中的 DBContext 和 DBContextOptionsConfigureServices
.ConfigureServices(services => {
    // Remove the app's ApplicationDbContext registration.
    var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof (DbContextOptions < MyDbContext > ));

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

    var descriptor2 = services.SingleOrDefault(d => d.ServiceType == typeof (MyDbContext));

    if (descriptor2 != null) {
        services.Remove(descriptor2);
    }

    //...
})
Run Code Online (Sandbox Code Playgroud)
  1. 添加您的后代上下文作为实现
.ConfigureServices(services => {
    // Remove the app's ApplicationDbContext registration.

    // ...
    services.AddDbContext < MyDbContext, MySqliteDbContext > (builder => {
        builder.UseSqlite(CreateInMemoryDatabase());
    }, ServiceLifetime.Singleton);
})
Run Code Online (Sandbox Code Playgroud)

注意:如果您使用 InMemory Sqlite,请考虑 Singleton 范围。

  1. 完毕。现在,DocumentComparisonContext注入DocumentComparisonSqlLiteContext将用作实现,并且EnsureCreated将使用特定于 sqlite 的逻辑。