繁体   English   中英

ASP.NET Core / EF Core / xUnit.NET 集成测试中每个测试的种子测试数据

[英]Seed test data for every test in ASP.NET Core / EF Core / xUnit.NET integration tests

我一直在遵循使用 ASP.NET Core 中的集成测试中的 Microsoft 文档为 ASP.NET Core 2.2 API 设置测试的策略。

总而言之,我们扩展和自定义WebApplicationFactory并使用IWebHostBuilder来设置和配置各种服务,以使用内存数据库为我们提供数据库上下文以进行如下测试(从文章中复制和粘贴):

public class CustomWebApplicationFactory<TStartup> 
    : WebApplicationFactory<TStartup> where TStartup: class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.ConfigureServices(services =>
        {
            // Create a new service provider.
            var serviceProvider = new ServiceCollection()
                .AddEntityFrameworkInMemoryDatabase()
                .BuildServiceProvider();

            // Add a database context (ApplicationDbContext) using an in-memory 
            // database for testing.
            services.AddDbContext<ApplicationDbContext>(options => 
            {
                options.UseInMemoryDatabase("InMemoryDbForTesting");
                options.UseInternalServiceProvider(serviceProvider);
            });

            // Build the service provider.
            var sp = services.BuildServiceProvider();

            // Create a scope to obtain a reference to the database
            // context (ApplicationDbContext).
            using (var scope = sp.CreateScope())
            {
                var scopedServices = scope.ServiceProvider;
                var db = scopedServices.GetRequiredService<ApplicationDbContext>();
                var logger = scopedServices
                    .GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();

                // Ensure the database is created.
                db.Database.EnsureCreated();

                try
                {
                    // Seed the database with test data.
                    Utilities.InitializeDbForTests(db);
                }
                catch (Exception ex)
                {
                    logger.LogError(ex, $"An error occurred seeding the " +
                        "database with test messages. Error: {ex.Message}");
                }
            }
        });
    }
}

在测试中,我们可以使用工厂并创建一个客户端,如下所示:

public class IndexPageTests : 
    IClassFixture<CustomWebApplicationFactory<RazorPagesProject.Startup>>
{
    private readonly HttpClient _client;
    private readonly CustomWebApplicationFactory<RazorPagesProject.Startup> 
        _factory;

    public IndexPageTests(
        CustomWebApplicationFactory<RazorPagesProject.Startup> factory)
    {
        _factory = factory;
        _client = factory.CreateClient(new WebApplicationFactoryClientOptions
            {
                AllowAutoRedirect = false
            });
    }

    [Fact]
    public async Task Test1()
    {
        var response = await _client.GetAsync("/api/someendpoint");
    }
}

这工作正常,但请注意对InitializeDbForTests的调用,它在配置服务时为所有测试设置一些测试数据。

我想要一个合理的策略,用干净的石板开始每个 API 测试,这样测试就不会相互依赖。 我一直在寻找各种方法来在我的测试方法中获取ApplicationDbContext无济于事。

在彼此完全隔离的情况下进行集成测试是否合理,我该如何使用 ASP.NET Core / EF Core / xUnit.NET 来处理它?

具有讽刺意味的是,您正在寻找EnsureDeleted而不是EnsureCreated 这将转储数据库。 由于内存中的“数据库”是无模式的,因此您实际上不需要确保它被创建甚至迁移。

此外,您不应为内存数据库使用硬编码名称。 这实际上会导致内存中的同一个数据库实例被到处使用。 相反,您应该使用随机的东西: Guid.NewGuid().ToString()就足够了。

好的,所以我让它工作了! 获得范围服务是关键。 当我想从头开始播种时,我可以通过将播种调用包装在using (var scope = _factory.Server.Host.Services.CreateScope()) { }部分开始每个测试,我可以在其中首先var scopedServices = scope.ServiceProvider; 然后var db = scopedServices.GetRequiredService<MyDbContext>(); db.Database.EnsureDeleted()并最终运行我的播种功能之前。 有点笨重,但它的工作原理。

感谢 Chris Pratt 的帮助(来自评论的回答)。

实际上, 使用 InMemory 进行测试在标题为“编写测试”的部分中非常好地描述了该过程。 这是一些说明基本思想的代码

    [TestClass]
public class BlogServiceTests
{
    [TestMethod]
    public void Add_writes_to_database()
    {
        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseInMemoryDatabase(databaseName: "Add_writes_to_database")
            .Options;

这个想法是每个测试方法都有一个单独的数据库,因此您不必担心测试的运行顺序或它们并行运行的事实。 当然,您必须添加一些代码来填充数据库并从每个测试方法中调用它。

我已经使用过这种技术并且效果很好。

暂无
暂无

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

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