C# 如何在单元测试之间重置EF7 InMemory提供程序?
我正在尝试使用EF7 InMemory提供程序进行单元测试,但是InMemory数据库在测试之间的持久性给我带来了问题 下面的代码演示了我的问题。一个测试有效,另一个测试总是失败。即使我在测试之间将C# 如何在单元测试之间重置EF7 InMemory提供程序?,c#,unit-testing,entity-framework-core,mstest,C#,Unit Testing,Entity Framework Core,Mstest,我正在尝试使用EF7 InMemory提供程序进行单元测试,但是InMemory数据库在测试之间的持久性给我带来了问题 下面的代码演示了我的问题。一个测试有效,另一个测试总是失败。即使我在测试之间将\u上下文设置为null,第二次测试运行中始终会有4条记录 [TestClass] public class UnitTest1 { private SchoolContext _context; [TestInitialize] public void Setup()
\u上下文
设置为null
,第二次测试运行中始终会有4条记录
[TestClass]
public class UnitTest1
{
private SchoolContext _context;
[TestInitialize]
public void Setup()
{
Random rng = new Random();
var optionsBuilder = new DbContextOptionsBuilder<SchoolContext>();
optionsBuilder.UseInMemoryDatabase();
_context = new SchoolContext(optionsBuilder.Options);
_context.Students.AddRange(
new Student { Id = rng.Next(1,10000), Name = "Able" },
new Student { Id = rng.Next(1,10000), Name = "Bob" }
);
_context.SaveChanges();
}
[TestCleanup]
public void Cleanup()
{
_context = null;
}
[TestMethod]
public void TestMethod1()
{
Assert.AreEqual(2, _context.Students.ToList().Count());
}
[TestMethod]
public void TestMethod2()
{
Assert.AreEqual(2, _context.Students.ToList().Count());
}
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SchoolContext : DbContext
{
public SchoolContext(DbContextOptions options) : base(options) { }
public DbSet<Student> Students { get; set; }
}
[TestClass]
公共类UnitTest1
{
私立学校背景(u context);;
[测试初始化]
公共作废设置()
{
随机rng=新随机();
var optionsBuilder=new DbContextOptionsBuilder();
optionsBuilder.UseInMemoryDatabase();
_上下文=新的学校上下文(optionsBuilder.Options);
_context.Students.AddRange(
新学生{Id=rng.Next(110000),Name=“Able”},
新学生{Id=rng.Next(110000),Name=“Bob”}
);
_SaveChanges();
}
[测试清理]
公共空间清理()
{
_上下文=空;
}
[测试方法]
公共void TestMethod1()
{
AreEqual(2,_context.Students.ToList().Count());
}
[测试方法]
公共void TestMethod2()
{
AreEqual(2,_context.Students.ToList().Count());
}
}
公立班学生
{
公共int Id{get;set;}
公共字符串名称{get;set;}
}
公共课堂背景:DbContext
{
公立学校上下文(DbContextOptions选项):基本(选项){}
公共数据库集学生{get;set;}
}
以下调用将清除内存中的数据存储
_context.Database.EnsureDeleted();
派对有点晚了,但我也遇到了同样的问题,但我最后做的是 为每个测试指定不同的数据库名称
optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
这样你就不必再加了
_context.Database.EnsureDeleted();
在你所有的测试中,我会选择两种答案的组合。如果测试并行运行,则可以在运行另一个测试的过程中删除一个数据库,所以在运行30个测试时,我看到零星的故障。 给它一个随机的db名称,并确保它在测试完成时被删除
public class MyRepositoryTests : IDisposable {
private SchoolContext _context;
[TestInitialize]
public void Setup() {
var options = new DbContextOptionsBuilder<ApplicationDbContext>()
// Generate a random db name
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString())
.Options;
_context = new ApplicationDbContext(options);
}
[TestCleanup]
public void Cleanup()
_context.Database.EnsureDeleted(); // Remove from memory
_context.Dispose();
}
}
公共类MyRepositoryTests:IDisposable{
私立学校背景(u context);;
[测试初始化]
公共作废设置(){
var options=new DbContextOptionsBuilder()
//生成一个随机的数据库名
.UseInMemoryDatabase(数据库名称:Guid.NewGuid().ToString())
.选择;
_上下文=新的ApplicationDbContext(选项);
}
[测试清理]
公共空间清理()
_context.Database.EnsureDeleted();//从内存中删除
_context.Dispose();
}
}
我使用
DbContext
夹具,如下所示
公共类DbContextFixture
其中TDbContext:DbContext
{
私有只读DbContextOptions_DbContextOptions=
新的DbContextOptionsBuilder()
.UseInMemoryDatabase(“\ux”,新的InMemoryDatabaseRoot())
.选择;
公共TDbContext CreateDbContext()
{
返回(TDbContext)(类型(TDbContext)
.GetConstructor(新[]{typeof(DbContextOptions)})
.Invoke(新[]{u dbContextOptions});
}
}
你现在可以简单地做
公共类MyRepositoryTests:IDisposable{
私立学校背景(u context);;
有关详细信息,请参阅专用DbContextFixture。只需更改DbContextOptions Builder的代码定义,如下所示:
var databaseName = "DatabaseNameHere";
var dbContextOption = new DbContextOptionsBuilder<SchoolContext>()
.UseInMemoryDatabase(databaseName, new InMemoryDatabaseRoot())
.Options;
此处的示例通过以下方式实现:
db..RemoveRange(db.);
下面是我的两分钱方法,以使每个单元测试彼此隔离。我使用的是C#7、XUnit和EF core 3.1
示例TestFixture类。
public class SampleIntegrationTestFixture : IDisposable
{
public DbContextOptionsBuilder<SampleDbContext> SetupInMemoryDatabase()
=> new DbContextOptionsBuilder<SampleDbContext>().UseInMemoryDatabase("MyInMemoryDatabase");
private IEnumerable<Student> CreateStudentStub()
=> new List<Student>
{
new Student { Id = rng.Next(1,10000), Name = "Able" },
new Student { Id = rng.Next(1,10000), Name = "Bob" }
};
public void Dispose()
{
}
}
公共类SampleIntegrationTestFixture:IDisposable
{
公共数据库上下文选项生成器SetupInMemoryDatabase()
=>新建DbContextOptionsBuilder().UseInMemoryDatabase(“MyInMemoryDatabase”);
私有IEnumerable CreateStudentStub()
=>新列表
{
新学生{Id=rng.Next(110000),Name=“Able”},
新学生{Id=rng.Next(110000),Name=“Bob”}
};
公共空间处置()
{
}
}
样本集成测试类
public class SampleJobIntegrationTest : IClassFixture<SampleIntegrationTestFixture >
{
private DbContextOptionsBuilder<SampleDbContext> DbContextBuilder { get; }
private SampleDbContext SampleDbContext { get; set; }
public SampleJobIntegrationTest(SampleIntegrationTestFixture
sampleIntegrationTestFixture )
{
SampleIntegrationTestFixture = sampleIntegrationTestFixture ;
SampleDbContextBuilder = sampleIntegrationTestFixture .SetupInMemoryDatabase();
}
[Fact]
public void TestMethod1()
{
using(SampleDbContext = new SampleDbContext(SampleDbContextBuilder.Options))
var students= SampleIntegrationTestFixture.CreateStudentStub();
{
SampleDbContext.Students.AddRange(students);
SampleDbContext.SaveChanges();
Assert.AreEqual(2, _context.Students.ToList().Count());
SampleDbContext.Database.EnsureDeleted();
}
}
公共类SampleJobIntegrationTest:IClassFixture
{
私有DbContextOptionsBuilderDbContextBuilder{get;}
私有SampleDbContext SampleDbContext{get;set;}
公共SampleJobIntegrationTest(SampleIntegrationTestFixture
sampleIntegrationTestFixture)
{
SampleIntegrationTestFixture=SampleIntegrationTestFixture;
SampleDbContextBuilder=sampleIntegrationTestFixture.SetupInMemoryDatabase();
}
[事实]
公共void TestMethod1()
{
使用(SampleDbContext=newsampledbcontext(SampleDbContextBuilder.Options))
var students=SampleIntegrationTestFixture.CreateStudentStub();
{
SampleDbContext.Students.AddRange(Students);
SampleDbContext.SaveChanges();
AreEqual(2,_context.Students.ToList().Count());
SampleDbContext.Database.EnsureDeleted();
}
}
谢谢,它解决了我的问题。我用缩写尝试了OptionBuilder.UseInMemoryDatabase(persist:false);已从EFCore中删除,然后偶然发现了另一种可能的解决方案,用于在此处测试之间具有不同的上下文:我更喜欢所选答案的简单性,但对于测试根合成,这似乎不会重置内存数据库的标识列。因此,如果您正在为数据播种一行,则第一个选项est将看到id为1的行,第二个测试2,等等。这是设计的吗?现在是2019年,即使在数据库被删除并重新创建之后,id仍然存在的问题仍然是一个问题!很好。这修复了我的问题!我以为我的错误是我的测试是并行运行的,但实际上是in-m
public class SampleIntegrationTestFixture : IDisposable
{
public DbContextOptionsBuilder<SampleDbContext> SetupInMemoryDatabase()
=> new DbContextOptionsBuilder<SampleDbContext>().UseInMemoryDatabase("MyInMemoryDatabase");
private IEnumerable<Student> CreateStudentStub()
=> new List<Student>
{
new Student { Id = rng.Next(1,10000), Name = "Able" },
new Student { Id = rng.Next(1,10000), Name = "Bob" }
};
public void Dispose()
{
}
}
public class SampleJobIntegrationTest : IClassFixture<SampleIntegrationTestFixture >
{
private DbContextOptionsBuilder<SampleDbContext> DbContextBuilder { get; }
private SampleDbContext SampleDbContext { get; set; }
public SampleJobIntegrationTest(SampleIntegrationTestFixture
sampleIntegrationTestFixture )
{
SampleIntegrationTestFixture = sampleIntegrationTestFixture ;
SampleDbContextBuilder = sampleIntegrationTestFixture .SetupInMemoryDatabase();
}
[Fact]
public void TestMethod1()
{
using(SampleDbContext = new SampleDbContext(SampleDbContextBuilder.Options))
var students= SampleIntegrationTestFixture.CreateStudentStub();
{
SampleDbContext.Students.AddRange(students);
SampleDbContext.SaveChanges();
Assert.AreEqual(2, _context.Students.ToList().Count());
SampleDbContext.Database.EnsureDeleted();
}
}