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

问题描述 投票:0回答:3

我需要替换 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());
    });
  });

但是因为我在测试中从 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'))");

            ...
        }
    }

有没有办法注入

MySqlLiteDbContext
而不是
MyDbContext
来强制EnsureCreated对SQLite使用
OnModelCreating
?提取
IMyDbContext
是一种选择吗?我还能做什么来解决这个问题?

unit-testing asp.net-core .net-core entity-framework-core
3个回答
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...
    }
  1. 删除
    WebApplicationFactory
    ConfigureServices
  2. 中的 DBContext 和 DBContextOptions
.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);
    }

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

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

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

  1. 完成。现在,当
    DocumentComparisonContext
    注入时,
    DocumentComparisonSqlLiteContext
    将用作实现,并且在
    EnsureCreated
    上将使用 sqlite 特定逻辑。

2
投票

向服务容器注册 DbContext。 打开 Startup.cs,在 ConfigureServices 函数中,我们将使用 AddDbContext 扩展方法来添加新的 DbContext,并告诉它使用来自 appsettings.json 的连接字符串的 SQLite。以下是完整的函数,前两行是我们添加的。

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ContactsDbContext>(options =>
        options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
    services.AddControllers();
    services.AddOpenApiDocument(document => 
        document.PostProcess = d => d.Info.Title = "Contacts API");
}

0
投票

感谢指导。不需要删除上下文,使用选项类就足够了。

var contextOptions = new DbContextOptionsBuilder<MyDbContext>()
            .UseInMemoryDatabase("<name>");
services.AddScoped<DbContextOptions<MyDbContext>>(_ => contextOptions.Options);
© www.soinside.com 2019 - 2024. All rights reserved.