【发布时间】:2020-06-16 00:47:33
【问题描述】:
我是新的 .NET Core 用户。我正在尝试对使用 EF Core 来管理数据的 ASP.NET.Core WebAPI 执行集成测试。架构基于eShopContainers DDD 示例。我正在使用 Xunit 进行测试,并考虑了三种方法将在 docker-compose 堆栈中运行的数据库重置为运行每个测试之前的初始状态:
- 测试设置:使用测试数据创建和种子数据库,TearDown:删除数据库。
- Test Setup:包含测试数据的种子数据库表,TearDown:清除测试数据。
- Test Setup:创建事务,TearDown:中止事务。
被测系统使用 BeginTransaction() 在事务中执行创建/删除/更新操作。不确定 EF Core 是否可以使用嵌套事务,因此在测试时尝试执行选项 1 和 2。
下面的代码使用 WebApiTestFactory 作为派生自WebApplicationFactory 的类。这是作为类夹具提供的,用于创建用于测试的 TestServer 实例。
public class CoursesScenarios : CoursesScenarioBase, IClassFixture<WebApiTestFactory>, IDisposable
{
/// <summary>
/// With Xunit constructor gets run before every test
/// Code in the Dispose method gets run after every test completed
/// </summary>
public CoursesScenarios(WebApiTestFactory factory) : base(factory)
{
Console.WriteLine("CoursesScenario test setup...");
Server.Host
.MigrateDbContext<CourseContext>((context, services) =>
{
Console.WriteLine("Seeding lookup data");
var env = services.GetService<IWebHostEnvironment>();
var settings = services.GetService<IOptions<CourseSettings>>();
var logger = services.GetService<ILogger<CoursesContextSeed>>();
new CoursesContextSeed()
.SeedAsync(context, env, settings, logger)
.Wait();
});
// load the test data
Server.Host
.MigrateDbContext<CourseContext>((context, services) =>
{
Console.WriteLine("Seeding the test data");
var env = services.GetService<IWebHostEnvironment>();
var settings = services.GetService<IOptions<CourseSettings>>();
var logger = services.GetService<ILogger<CoursesContextTestSeed>>();
new CoursesContextTestSeed()
.SeedAsync(context, env, settings, logger)
.Wait();
});
foreach(Course c in Context.Courses)
{
Console.WriteLine($"Course {c.Id}");
}
}
// tests here
[Fact]
...
//
///
/// <summary>
/// This gets called after every test by XUnit
/// </summary>
///
public void Dispose()
{
// using (var command = Context.Database.GetDbConnection().CreateCommand())
// {
// command.CommandText = @"DELETE FROM CourseManagement.Course;
// ALTER SEQUENCE coursemanagement.""unit_UnitID_seq"" RESTART WITH 1;";
// Context.Database.OpenConnection();
// int result = command.ExecuteNonQuery();
// Console.WriteLine($"{result} records deleted from course table");
// how to reload entities to match deleted state of rows in table?
// currently entities in memory are saved back to database
// }
Context.Database.EnsureDeleted();
}
以下异常在服务器上引发并在测试期间收到。这是由于删除了数据库,所以连接丢失了。
Npgsql.NpgsqlException (0x80004005): Exception while connecting
---> System.Net.Sockets.SocketException (111): Connection refused
at Npgsql.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.NpgsqlConnector.Connect(NpgsqlTimeout timeout)
at Npgsql.NpgsqlConnector.RawOpen(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnector.Open(NpgsqlTimeout timeout, Boolean async, CancellationToken cancellationToken)
at Npgsql.NpgsqlConnection.<>c__DisplayClass32_0.<<Open>g__OpenLong|0>d.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at Npgsql.NpgsqlConnection.Open()
at Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlDatabaseCreator.Exists()
at Microsoft.EntityFrameworkCore.Migrations.HistoryRepository.Exists()
at Microsoft.EntityFrameworkCore.Migrations.Internal.Migrator.Migrate(String targetMigration)
at Microsoft.EntityFrameworkCore.RelationalDatabaseFacadeExtensions.Migrate(DatabaseFacade databaseFacade)
at Microsoft.AspNetCore.Hosting.IWebHostExtensions.InvokeSeeder[TContext](Action`2 seeder, TContext context, IServiceProvider services) in /src/BuildingBlocks/WebHost.Customization/IWebHostExtensions.cs:line 76
at Microsoft.AspNetCore.Hosting.IWebHostExtensions.<>c__DisplayClass1_0`1.<MigrateDbContext>b__2() in /src/BuildingBlocks/WebHost.Customization/IWebHostExtensions.cs:line 54
at Polly.Policy.<>c__DisplayClass108_0.<Execute>b__0(Context ctx, CancellationToken ct)
at Polly.Policy.<>c__DisplayClass138_0.<Implementation>b__0(Context ctx, CancellationToken token)
at Polly.Retry.RetryEngine.Implementation[TResult](Func`3 action, Context context, CancellationToken cancellationToken, ExceptionPredicates shouldRetryExceptionPredicates, ResultPredicates`1 shouldRetryResultPredicates, Action`4 onRetry, Int32 permittedRetryCount, IEnumerable`1 sleepDurationsEnumerable, Func`4 sleepDurationProvider)
是否有人设法使用 EF Core 成功重置数据库状态以进行集成测试,无论是使用删除数据库方法还是种子/取消种子表状态?还尝试了种子数据/非种子数据方法,重置身份密钥并使用原始 SQL 查询删除记录,但随后在将 EF Core 与基础表中已删除行的状态重新同步时遇到了困难,EF Core 将它们视为新实体并添加他们回来了。也许最好的方法是使用测试数据 sql 脚本和 ADO.NET 来初始化测试数据状态?
【问题讨论】:
-
请查看github.com/v-zubritsky/Reseed 是否有帮助
标签: c# asp.net-core entity-framework-core