ASP.NET Core 2.2集成测试:DbContext服务未注册

3

安装

  • Windows 10
  • Visual Studio Professional 2017 v15.9.9
  • ASP.NET Core 2.2
  • EF Core 2.2
  • Dapper
  • xUnit 2.4.1

描述

我正在使用来自Microsoft.AspNetCore.Mvc.Testing包的WebApplicationFactory来设置我的集成测试。

我一直在遵循官方文档来自定义Web主机配置。

系统使用Dapper从数据库查询,因此我在这个特定的集成测试中不使用随EF Core一起提供的In-Memory提供程序。

以下是设置WebApplictionFactory的代码:

public class CustomWebApplicationFactory<TStartup>
    : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder
            .UseStartup<TStartup>()
            .ConfigureServices(services =>
        {
            var sp = services.BuildServiceProvider();

            // Create a scope to obtain a reference to the database context
            using (var scope = sp.CreateScope())    
            {
                var scopedServices = scope.ServiceProvider;
                var dbContext = scopedServices.GetRequiredService<MyDbContext>(); // <-- service not found

                dbContext.Database.EnsureCreated();

                new MyDbContextSeed()
                    .SeedAsync(dbContext)
                    .Wait();
            }
        });
    }
}

问题

无法找到MyDbContext服务,我理解原因(我认为是)- 因为我的Startup.cs类中的ServiceProvider尚未构建。

但问题是我如何在此处从我的启动类访问服务?

为了上下文,集成测试看起来像这样:

public class MyAPITests
    : IClassFixture<CustomWebApplicationFactory<Startup>>
{
    private readonly HttpClient _client;
    private readonly CustomWebApplicationFactory<Startup> _factory;

    public MyAPITests(CustomWebApplicationFactory<Startup> factory)
    {
        _factory = factory;
        _client = factory.CreateClient();
    }

    [Fact]
    public async Task Get_ItemAsync_WhenIdNotFound_ReturnsNotFoundStatusCode()
    {
        // Arrange
        var request = new HttpRequestMessage(HttpMethod.Get, "api/v1/item/0");

        // Act
        var response = await _client.SendAsync(request);

        // Assert
        Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
    }
}

DbContext是Entity,因此您需要创建数据库到c#类的映射。这可以通过使用Visual Studio菜单:Data:Add New Data Source自动完成。 - jdweng
1个回答

2
首先,可以使用ConfigureServices代替UseStartup,但不能同时使用。其次,在ConfigureServices期间不应创建范围并执行迁移,而是在Web主机构建之后进行,参见此处

在旧版教程中,您可能会在Startup.cs文件的Configure方法中看到类似的代码。我们建议您仅使用Configure方法来设置请求管道。应用程序启动代码应放在Main方法中。

唯一的方法是在工厂之后进行,而不是在工厂中:
public class MyAPITests
    : IClassFixture<CustomWebApplicationFactory<Startup>>
{
    private readonly HttpClient _client;
    private readonly CustomWebApplicationFactory<Startup> _factory;

    public MyAPITests(CustomWebApplicationFactory<Startup> factory)
    {
        _factory = factory;
        _client = factory.CreateClient();

        var host = factory.Server.Host;
        using (var scope = host.Services.CreateScope())
        {
            var scopedServices = scope.ServiceProvider;
            var dbContext = scopedServices.GetRequiredService<MyDbContext>();

            dbContext.Database.EnsureCreated();

            new MyDbContextSeed()
                .SeedAsync(dbContext)
                .Wait();
        }
    }

    //...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接