在 Xunit 集成测试中检索 ASP.NET 核心 3.1 数据库上下文
Retrieving ASP.NET Core 3.1 database context in Xunit integration test
我一直在使用 Xunit 为使用数据库的 .NET Core 3.1 Web 应用程序创建集成测试。为了进行测试,我已从 Microsoft Documentation 切换到内存数据库。 CustomWebApplicationFactory 代码是:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder webHostBuilder)
{
webHostBuilder.ConfigureServices(services =>
{
// Remove the app's database registration.
var serviceDescriptor = services
.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>));
if (serviceDescriptor != null)
{
services.Remove(serviceDescriptor);
}
// Add MyDbContext using an in-memory database for testing.
services.AddDbContext<MyDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
var servicesProvider = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context (MyDbContext).
using (var serviceScope = servicesProvider.CreateScope())
{
var scopedServices = serviceScope.ServiceProvider;
var db = scopedServices.GetRequiredService<MyDbContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureCreated(); // Ensure the database is created.
try
{
DatabaseSeeding.voidInitialiseCazIdentityProviderDatabase(db); // Seed the database with test data.
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with data. Error: {ex.Message}");
}
}
});
}
我的基本页面测试在这种安排下运行良好,但我现在想检查内存数据库是否已通过集成测试进行更正修改。无论发生什么,对数据库的引用都不会在 Xunit DI 容器中结束(如果存在的话)。我的测试 class 使用以下代码初始化:
public class IdpUserServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
private readonly ITestOutputHelper _testOutput;
private readonly HttpClient _httpClient;
private readonly MyDbContext _myDbContext;
public IdpUserServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, MyDbContext myDbContext, ITestOutputHelper testOutput)
{
_webApplicationFactory = webApplicationFactory;
_myDbContext = myDbContext;
_testOutput = testOutput;
_httpClient = _webApplicationFactory.CreateClient();
}
//Tests
但是在尝试 运行 测试时,我收到以下错误:
The following constructor parameters did not have matching fixture data: MyDbContext objMyDbContext
我正在寻找访问内存数据库的正确方法——显然不是通过构造函数注入。我已经尝试过这个答案 - - 但事情似乎在 2.2 和 3.1 之间发生了变化。
事实证明,上面提到的 Access in memory dbcontext in integration test 答案对于 ASP.NET Core 3.1[=19 不太正确=]. scopeFactory 必须从不同的来源找到:
var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();
所以测试 class 现在看起来像:
public class ServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
private readonly ITestOutputHelper _testOutput;
private readonly HttpClient _httpClient;
public ServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, ITestOutputHelper testOutput)
{
_webApplicationFactory = webApplicationFactory;
_testOutput = testOutput;
_httpClient = _webApplicationFactory.CreateClient();
}
[Fact]
public async Task AServiceTest()
{
// Do some HTTP client stuff that alters the in-memory database
var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();
using(var scope = scopeFactory.CreateScope())
{
var myDataContext = scope.ServiceProvider.GetService<MyDataContext>();
// Query the in-memory database
}
}
}
我一直在使用 Xunit 为使用数据库的 .NET Core 3.1 Web 应用程序创建集成测试。为了进行测试,我已从 Microsoft Documentation 切换到内存数据库。 CustomWebApplicationFactory 代码是:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder webHostBuilder)
{
webHostBuilder.ConfigureServices(services =>
{
// Remove the app's database registration.
var serviceDescriptor = services
.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<MyDbContext>));
if (serviceDescriptor != null)
{
services.Remove(serviceDescriptor);
}
// Add MyDbContext using an in-memory database for testing.
services.AddDbContext<MyDbContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
var servicesProvider = services.BuildServiceProvider();
// Create a scope to obtain a reference to the database context (MyDbContext).
using (var serviceScope = servicesProvider.CreateScope())
{
var scopedServices = serviceScope.ServiceProvider;
var db = scopedServices.GetRequiredService<MyDbContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureCreated(); // Ensure the database is created.
try
{
DatabaseSeeding.voidInitialiseCazIdentityProviderDatabase(db); // Seed the database with test data.
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occurred seeding the database with data. Error: {ex.Message}");
}
}
});
}
我的基本页面测试在这种安排下运行良好,但我现在想检查内存数据库是否已通过集成测试进行更正修改。无论发生什么,对数据库的引用都不会在 Xunit DI 容器中结束(如果存在的话)。我的测试 class 使用以下代码初始化:
public class IdpUserServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
private readonly ITestOutputHelper _testOutput;
private readonly HttpClient _httpClient;
private readonly MyDbContext _myDbContext;
public IdpUserServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, MyDbContext myDbContext, ITestOutputHelper testOutput)
{
_webApplicationFactory = webApplicationFactory;
_myDbContext = myDbContext;
_testOutput = testOutput;
_httpClient = _webApplicationFactory.CreateClient();
}
//Tests
但是在尝试 运行 测试时,我收到以下错误:
The following constructor parameters did not have matching fixture data: MyDbContext objMyDbContext
我正在寻找访问内存数据库的正确方法——显然不是通过构造函数注入。我已经尝试过这个答案 -
事实证明,上面提到的 Access in memory dbcontext in integration test 答案对于 ASP.NET Core 3.1[=19 不太正确=]. scopeFactory 必须从不同的来源找到:
var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();
所以测试 class 现在看起来像:
public class ServiceTests : IClassFixture<CustomWebApplicationFactory<Startup>>
{
private readonly CustomWebApplicationFactory<Startup> _webApplicationFactory;
private readonly ITestOutputHelper _testOutput;
private readonly HttpClient _httpClient;
public ServiceTests(CustomWebApplicationFactory<Startup> webApplicationFactory, ITestOutputHelper testOutput)
{
_webApplicationFactory = webApplicationFactory;
_testOutput = testOutput;
_httpClient = _webApplicationFactory.CreateClient();
}
[Fact]
public async Task AServiceTest()
{
// Do some HTTP client stuff that alters the in-memory database
var scopeFactory = _webApplicationFactory.Services.GetService<IServiceScopeFactory>();
using(var scope = scopeFactory.CreateScope())
{
var myDataContext = scope.ServiceProvider.GetService<MyDataContext>();
// Query the in-memory database
}
}
}