繁体   English   中英

如何在 TestContainers 中自动设置 Entity Framework 的 Code First 数据库以进行测试?

[英]How to automate DB setup of Entity Framework's Code First in TestContainers for testing?

为了设置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()

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

dbContext.Database.Migrate();

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

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

我有一个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);
    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM