我正在以这种方式自定义WebApplicationFactory以覆盖SQLServer中的数据库(我希望数据库位于内存中):
history
并且我使用WebHostBuilderExtensions重置数据库(确保所有测试数据库均为默认状态):
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
private readonly InMemoryDatabaseRoot _dbRoot = new InMemoryDatabaseRoot();
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureTestServices(services =>
{
var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<TestContext>));
if (descriptor != null)
{
services.Remove(descriptor);
}
services.AddDbContext<TestContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting", _dbRoot);
});
var sp = services.BuildServiceProvider();
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<TestContext>();
var logger = scopedServices.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureCreated();
try
{
DatabaseHelper.InitialiseDbForTests(db);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occured seeding the database with test data. Error: {ex.Message}");
}
}
});
}
}
测试是:
public static class WebHostBuilderExtensions
{
public static IWebHostBuilder ConfigureTestDatabase(this IWebHostBuilder builder, Action<TestContext> configure)
{
return builder.ConfigureTestServices(services =>
{
var sp = services.BuildServiceProvider();
using var scope = sp.CreateScope();
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<TestContext>();
var logger = scopedServices.GetRequiredService<ILogger<TestControllerTests>>();
try
{
configure(db);
}
catch (Exception ex)
{
logger.LogError(ex, $"An error occured setting up the database for the test. Error: {ex.Message}");
}
});
}
}
public static HttpClient CreateClientAndDbSetup(this WebApplicationFactory<Startup> factory, Action<TestContext> configure, string token)
{
var client = factory.WithWebHostBuilder(builder =>
{
builder.ConfigureTestDatabase(configure);
}).CreateClient();
return client;
}
程序:
[Fact]
public async Task Get_ShouldReturnOk()
{
var client = _factory.CreateClientAndDbSetup(db => DatabaseHelper.RestetDbForTests(db), _token);
var response = await client.GetAsync($"{_endPoint}");
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
基于https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1
的代码问题在于,对于所有测试,在初始化数据库之前正在执行将数据库还原到原始状态的操作。这意味着首先要从 WebHostBuilderExtensions 执行 ConfigureTestDatabase ,而不是从 CustomWebApplicationFactory 执行 ConfigureWebHost ,所以在第一次测试中可能是原始sql数据库将被重置。
CustomWebApplicationFactoru中的ConfigureWebHost方法应该对所有测试执行一次还是对每个测试执行?
有解决此问题的主意吗?