EF7 InMemoryプロバイダーを単体テストに使用しようとしていますが、テスト間のInMemoryデータベースの永続的な性質が問題を引き起こしています。
次のコードは私の問題を示しています。 1つのテストが機能し、他のテストは常に失敗します。テスト間で_contextをnullに設定しても、2回目のテスト実行では常に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; }
}
次の呼び出しは、メモリ内のデータストアをクリアします。
_context.Database.EnsureDeleted();
パーティーに少し遅れましたが、私も同じ問題に遭遇しましたが、私がやったことは終わりました。
テストごとに異なるデータベース名を指定します。
optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
そのように追加する必要はありません
_context.Database.EnsureDeleted();
すべてのテストで
私は両方の答えを組み合わせて行きます。テストを並行して実行すると、別のテストの実行中にデータベースが削除される可能性があるため、30以上のテストを実行すると散発的なエラーが発生していました。
ランダムなデータベース名を付け、テストの完了時に削除されるようにします。
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();
}
}
次のようなDbContext
フィクスチャを使用します
public class DbContextFixture
where TDbContext : DbContext
{
private readonly DbContextOptions _dbContextOptions =
new DbContextOptionsBuilder()
.UseInMemoryDatabase("_", new InMemoryDatabaseRoot())
.Options;
public TDbContext CreateDbContext()
{
return (TDbContext)(typeof(TDbContext)
.GetConstructor(new[] { typeof(DbContextOptions) })
.Invoke(new[] { _dbContextOptions }));
}
}
あなたは今やることができます
public class MyRepositoryTests : IDisposable {
private SchoolContext _context;
private DbContextFixture<ApplicationDbContext> _dbContextFixture;
[TestInitialize]
public void Setup() {
_dbContextFixture = new DbContextFixture<ApplicationDbContext>();
_context = _dbContextFixture.CreateDbContext();
_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.Dispose();
_dbContextFixture = null;
}
[TestMethod]
public void TestMethod1()
{
Assert.AreEqual(2, _context.Students.ToList().Count());
}
[TestMethod]
public void TestMethod2()
{
Assert.AreEqual(2, _context.Students.ToList().Count());
}
}
このソリューションはスレッドセーフです。詳細については、私の blog を参照してください。