unit-testing - test - tipos de pruebas unitarias
¿Cómo puedo restablecer un proveedor EF7 InMemory entre pruebas unitarias? (5)
Estoy tratando de usar el proveedor EF7 InMemory para pruebas unitarias, pero la naturaleza persistente de la base de datos InMemory entre pruebas me está causando problemas.
El siguiente código demuestra mi problema. Una prueba funcionará y la otra prueba siempre fallará. Aunque configuré el _context como nulo entre pruebas, la segunda ejecución de prueba siempre tendrá 4 registros.
[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; }
}
La siguiente llamada borrará el almacén de datos en memoria.
_context.Database.EnsureDeleted();
Simplemente cambie su definición de código de DbContextOptionsBuilder para que sea como sigue:
var databaseName = "DatabaseNameHere";
var dbContextOption = new DbContextOptionsBuilder<SchoolContext>()
.UseInMemoryDatabase(databaseName, new InMemoryDatabaseRoot())
.Options;
new InMemoryDatabaseRoot () Está creando una nueva base de datos sin que la identificación persista. Entonces no necesitas ahora para:
[TestCleanup]
public void Cleanup()
{
_context = null;
}
Un poco tarde para la fiesta, pero también me encontré con el mismo problema, pero lo que terminé haciendo fue.
Especificar un nombre de base de datos diferente para cada prueba.
optionsBuilder.UseInMemoryDatabase(Guid.NewGuid().ToString());
De esa manera no tienes que agregar
_context.Database.EnsureDeleted();
en todas tus pruebas
Yo iría con una combinación de ambas respuestas. Si las pruebas se ejecutan en paralelo, es posible que se elimine una base de datos mientras está ejecutando otra prueba, por lo que vi fallas esporádicas al ejecutar más de 30 pruebas.
Déle un nombre de base de datos aleatorio y asegúrese de que se elimine cuando se complete la prueba.
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();
}
}
Yo uso un accesorio
DbContext
como el siguiente
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 }));
}
}
ahora puedes simplemente hacer
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());
}
}
Esta solución es segura para subprocesos. Vea mi blog para más detalles.