首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ASP.NET核心/ EF核心/ xUnit.NET集成测试中每个测试的种子测试数据

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

Stack Overflow用户
提问于 2019-04-23 20:22:49
回答 3查看 5.8K关注 0票数 5

我一直在遵循使用Integration tests in ASP.NET Core上的ASP.NET文档为MicrosoftCore2.2API设置测试的策略。

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

代码语言:javascript
复制
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}");
                }
            }
        });
    }
}

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

代码语言:javascript
复制
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核心/ EF核心/ xUnit.NET进行集成测试?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2019-10-01 14:37:30

好的,所以我让它工作了!获取作用域服务是关键。当我想从头开始做种子时,我可以在每个测试开始时将种子调用包装在using (var scope = _factory.Server.Host.Services.CreateScope()) { }部分中,在这个部分中,我可以先var scopedServices = scope.ServiceProvider;,然后var db = scopedServices.GetRequiredService<MyDbContext>();,然后db.Database.EnsureDeleted(),最后运行我的种子函数。有点笨拙,但它很管用。

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

票数 1
EN

Stack Overflow用户

发布于 2019-04-23 21:17:41

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

此外,您不应该对内存中的数据库使用硬编码名称。这实际上会导致内存中的相同数据库实例在任何地方都被使用。相反,你应该使用一些随机的东西:Guid.NewGuid().ToString()已经足够好了。

票数 6
EN

Stack Overflow用户

发布于 2019-04-25 20:07:26

实际上,Testing with InMemory在标题为“编写测试”的部分中很好地描述了这个过程。下面是一些说明基本思想的代码

代码语言:javascript
复制
    [TestClass]
public class BlogServiceTests
{
    [TestMethod]
    public void Add_writes_to_database()
    {
        var options = new DbContextOptionsBuilder<BloggingContext>()
            .UseInMemoryDatabase(databaseName: "Add_writes_to_database")
            .Options;

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

我已经使用过这种技术,它工作得很好。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55811147

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档