Ich versuche, den EF7 InMemory-Anbieter für Komponententests zu verwenden, aber die Beständigkeit der InMemory-Datenbank zwischen den Tests verursacht mir Probleme.
Der folgende Code zeigt mein Problem. Ein Test funktioniert und der andere Test schlägt immer fehl. Obwohl ich den _context zwischen den Tests auf null gesetzt habe, enthält der zweite Testlauf immer 4 Datensätze.
[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; }
}
unit-testing
mstest
entity-framework-core
Segeln Judo
quelle
quelle
[TearDown]
(das läuft nach jedem Test).Etwas spät zur Party, aber ich bin auch auf das gleiche Problem gestoßen, aber am Ende habe ich es getan.
Angabe eines anderen Datenbanknamens für jeden Test.
Auf diese Weise müssen Sie nicht hinzufügen
in all deinen Tests
quelle
EnsureDeleted
, muss dies nur einmal in der[TearDown]
Methode hinzufügen , die nach jedem Test ausgeführt wird, so dass kein großer Schmerz.Ändern Sie einfach Ihre Codedefinition von DbContextOptionsBuilder wie folgt:
new InMemoryDatabaseRoot () erstellt eine neue Datenbank, ohne dass das Problem der ID bestehen bleibt . Sie brauchen jetzt also nicht für:
quelle
Ich würde mit einer Kombination beider Antworten gehen. Wenn Tests parallel ausgeführt werden, wird möglicherweise eine Datenbank gelöscht, während Sie gerade einen weiteren Test ausführen. Daher traten beim Ausführen von mehr als 30 Tests sporadische Fehler auf.
Geben Sie ihm einen zufälligen Datenbanknamen und stellen Sie sicher, dass er nach Abschluss des Tests gelöscht wird.
quelle
Ich benutze ein
DbContext
Gerät wie das folgendepublic 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 })); } }
Sie können jetzt einfach tun
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()); } }
Diese Lösung ist threadsicher. Siehe meinen Blog für Details.
quelle
Die Beispiele hier erreichen dies durch RemoveRange: https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-3.1
quelle
Hier ist mein 2-Cent-Ansatz, um jeden Unit-Test voneinander isoliert zu halten. Ich verwende C # 7, XUnit und EF Core 3.1.
Beispiel-TestFixture-Klasse.
Beispiel für eine IntegrationTest-Klasse
quelle