【问题标题】:Replace DbContext in WebApplicationFactory for unit testing替换 WebApplicationFactory 中的 DbContext 进行单元测试
【发布时间】:2021-08-24 19:49:33
【问题描述】:

我需要在 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 使用 OnModelCreating 用于 SQLite?提取IMyDbContext 是一种选择吗?我还能做些什么来解决这个问题?

【问题讨论】:

    标签: unit-testing asp.net-core .net-core entity-framework-core


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      好的,看来我设法解决了这个问题

      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. 删除WebApplicationFactoryConfigureServices 中的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 的逻辑。

      【讨论】:

        猜你喜欢
        • 2021-03-15
        • 2011-10-09
        • 2011-07-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-06-16
        • 2014-09-07
        • 1970-01-01
        相关资源
        最近更新 更多