【问题标题】:How to automate DB setup of Entity Framework's Code First in Testcontainers for testing?如何在 TestContainers 中自动设置 Entity Framework\'s Code First 的数据库以进行测试?
【发布时间】:2022-12-13 20:07:04
【问题描述】:

为了设置 TestContainerMsSqlTestcontainer 进行测试,我复制了 dotnet ef migrations script 发出的脚本并将其植入单元测试的设置中(实际代码没有:

void PrepareDb(MsSqlTestcontainer dbTestContainer){
    dbTestContainer.ExecScriptAsync(@"CREATE TABLE [DbName] ( /* ... */ )");
}

有没有办法让它自动化,例如,如果数据库模型发生变化,并连接起来,例如MyDbContext直接进入TestContainer的逻辑?

我正在考虑将 MyDbContext 代码传递到容器中并在其中运行 dotnet ef migrations script,但我不确定这值得多少努力(我需要使用已经安装了 dotnet 的容器,这是另一个并发症..)。

这是 dbTestContainer 设置,FWIW:

var dbTestContainer = new TestcontainersBuilder<MsSqlTestcontainer>()
    .WithDatabase(new MsSqlTestcontainerConfiguration { Password = "whatever secret" })
    .WithImage("mcr.microsoft.com/azure-sql-edge")
    .WithWaitStrategy(Wait.ForUnixContainer())
    .Build()

【问题讨论】:

    标签: c# entity-framework ef-code-first code-first testcontainers


    【解决方案1】:

    连接到容器化数据库并在测试开始之前以编程方式运行迁移

    dbContext.Database.Migrate();

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题,但我设法解决了它,至少是为了满足我自己的基本需求。如果您仍然需要解决方案,这就是我所做的。

      注意:如果有人知道更好的方法或发现以下任何缺陷,我将非常高兴听到。

      我有一个IntegrationTestWebApplicationFactory,我用它来为我的集成测试做通常的配置。正如 Pavel 已经指出的那样,您可以在测试开始之前以编程方式运行迁移。为此,我的IntegrationTestWebApplicationFactory实现了XUnitIAsyncLifetime接口,我正在使用它进行测试。这个接口要求你实现InitializeAsyncDisposeAsync方法。在 InitializeAsync 中,我运行 await dbContext.Database.MigrateAsync(); 命令。

      这是我的IntegrationTestWebApplicationFactory 类的完整代码:

      public class IntegrationTestWebApplicationFactory : WebApplicationFactory<Program>, IAsyncLifetime
      {
          private readonly TestcontainerDatabase _container;
      
          public IntegrationTestFactory()
          {
              _container = new TestcontainersBuilder<MsSqlTestcontainer>()
                  .WithDatabase(new MsSqlTestcontainerConfiguration
                  {
                      Username = "sa",
                      Database = "WeatherApp",
                      Password = "2@LaiNw)PDvs^t>L!Ybt]6H^%h3U>M",
                  })
                  .WithImage("mcr.microsoft.com/mssql/server:2022-latest")
                  .WithCleanUp(true)
                  .Build();
          }
      
          protected override void ConfigureWebHost(IWebHostBuilder builder)
          {
              builder.ConfigureTestServices(services =>
              {
                  services.AddDbContext<DemoDbContext>(options => { options.UseSqlServer(_container.ConnectionString); });
              });
          }
      
          public async Task InitializeAsync()
          {
              await _container.StartAsync();
              using var scope = Services.CreateScope();
              var dbContext = scope.ServiceProvider.GetRequiredService<DemoDbContext>();
              await dbContext.Database.MigrateAsync();
          }
      
          public new async Task DisposeAsync() => await _container.DisposeAsync();
      }
      

      这就是我在集成测试中使用它的方式:

          [Theory]
          [InlineAutoData]
          public async Task GettingWeatherForecastReturnsOkay(WeatherForecast expectedForecast)
          {
              var client = _integrationTestFactory.CreateClient();
      
              // insert into db what you want to assert
              await client.PostAsJsonAsync("WeatherForecast", expectedForecast);
              
              // read from db
              var forecasts = await client.GetFromJsonAsync<List<WeatherForecast>>("WeatherForecast");
      
              // do asserts or whatever..
              forecasts.Should().NotBeEmpty();
              forecasts.Should().ContainEquivalentOf(expectedForecast);
          }
      

      【讨论】:

        猜你喜欢
        • 2015-04-15
        • 1970-01-01
        • 2012-08-16
        • 2014-11-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-22
        • 1970-01-01
        相关资源
        最近更新 更多