我想在每个单元测试中创建干净的内存数据库。 当我运行多个测试时,先前测试的数据仍保留在数据库中。如何处置现有的内存数据库?
我使用以下代码初始化每个测试:
[TestInitialize]
public void TestInitialize()
{
Services = new ServiceCollection();
Services.AddScoped<DbContextOptions<MyDbContext>>(sp => new DbContextOptionsBuilder<TacsDbContext>()
.UseInMemoryDatabase("MyTestDbContext")
.Options);
Services.AddTransient<InMemoryMyDbContext>();
Services.AddTransient<MyDbContext>(sp => sp.GetService<InMemoryTacsDbContext>());
ServiceProvider = Services.BuildServiceProvider();
}
[TestMethod]
public void Test1()
{
using (var dbContext = ServiceProvider.GetService<MyDbContext>()) ...
}
[TestMethod]
public void Test2()
{
using (var dbContext = ServiceProvider.GetService<MyDbContext>()) ...
}
我使用.NET Core 2.0和Entity Framework Core 2.0
修改
我无法使用标准注册:Services.AddDbContext<InMemoryMyDbContext>(...)
,因为
public class InMemoryMyDbContext : MyDbContext
{
public InMemoryMyDbContext(DbContextOptions<InMemoryMyDbContext> options)
: base(options) { } //compiler error
public InMemoryMyDbContext(DbContextOptions<MyDbContext> options)
: base(options) { } //runtime IoC error
}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options) { }
}
答案 0 :(得分:1)
好的,我的解决方案是调用 DbContextOptionsBuilder.UseApplicationServiceProvider()
Services.AddScoped<DbContextOptions<MyDbContext>>(sp => new DbContextOptionsBuilder<MyDbContext>()
.UseApplicationServiceProvider(sp)
.UseInMemoryDatabase("Test")
.Options);
当您使用usuall方式设置ServiceCollection时会自动调用此方法,因此在以下情况下,每次都从头开始创建数据库
Services.AddDbContext<MyDbContext>(options => options.UseInMemoryDatabase("Test"));
最后,我能够修改MyDbContext,以便我调用上面的行:
public class MyDbContext : DbContext
{
protected MyDbContext (DbContextOptions options) : base(options) { }
public MyDbContext (DbContextOptions<MyDbContext> options)
: this((DbContextOptions)options) { }
}
public class InMemoryMyDbContext : TacsDbContext
{
public InMemoryMyDbContext (DbContextOptions<InMemoryTacsDbContext> options)
: base(options) { }
}
Services.AddDbContext<InMemoryMyDbContext>(options =>
options.UseInMemoryDatabase("Test"), ServiceLifetime.Transient);
Services.AddTransient<MyDbContext>(sp => sp.GetService<InMemoryMyDbContext>());
答案 1 :(得分:0)
考虑使用Nuget包努力
这是一个简单的快速内存数据库,非常适合单元测试
您可以使用空数据库启动它;如果需要,可以使用数据库播种器填充它,或者将其填入测试CSV文件中的值。
请参阅Tutorials Effort - Entity Framework Unit Testing Tool
您的DbContext可能类似于:
class MyDbContext : DbContext
{
public MyDbContext() : base() { } // constructor using config file
public BloggingContext(string nameOrConnectionString) :
base(nameOrConnectionString) { }
public DbSet<...> ...{ get; set; }
public DbSet<...> ...{ get; set; }
}
只需添加一个构造函数,就可以像使用原始数据库一样使用内存数据库:
public MyDbContext(DbConnection connection) : base(connection, true) { }
您将DbConnection传递给测试数据库,此连接将传递给DbContext类。 true参数表示当DbContext被释放时,DbConnection也应该是Disposed。
用法是:
[TestMethod]
public void UnitTest_X()
{
var dbConnection = Effort.DbConnectionFactory.CreateTransient();
using (var dbContext = new MyDbContext(dbConnection)
{
// perform your test of MyDbContext as if it was connected to your
// original database
}
}
可以找到具有使用一对多关系的Effort数据库的控制台程序的简单复制粘贴代码示例here on StackOverFlow