I have stumbled across these unit tests in a code review that are using in memory db:
private DatabaseContext _context;
private Fixture _fixture;
[SetUp]
public void Setup()
{
_fixture = new Fixture();
_fixture.Customize(new AutoNSubstituteCustomization());
var options = new DbContextOptionsBuilder<DatabaseContext>()
.UseInMemoryDatabase(databaseName: "testdb")
.Options;
_context = new DatabaseContext(options);
}
[TearDown]
public void CleanUp()
{
var context = _context;
if (context == null || context.Database.ProviderName != "Microsoft.EntityFrameworkCore.InMemory")
{
return;
}
context.Database.EnsureDeleted();
_context = null;
}
#region EmptyDB
[Test]
public void Test1()
{
// Setup
var logger = _fixture.Freeze<ILogger<UserRepository>>();
var userRepo = new UserRepository(_context, logger);
var userViews = new List<UserView>();
userViews.AddRange(_fixture.CreateMany<UserView>(10));
// ACT
userRepo.UpdateUsers(userViews, CancellationToken.None).GetAwaiter().GetResult();
// ASSERT
Assert.AreEqual(10, _context.Users.CountAsync().GetAwaiter().GetResult());
}
[Test]
public void Test2()
{
// Setup
var logger = _fixture.Freeze<ILogger<UserRepository>>();
var userRepo = new UserRepository(_context, logger);
var identityViews = new List<IdentityView>();
_fixture.Register<IEnumerable<UserView>>(() =>
{
return new UserView[] { new UserView("fish") };
});
userViews.AddRange(_fixture.CreateMany<UserView>(10));
// ACT
userRep.UpdateUsers(userViews, CancellationToken.None).GetAwaiter().GetResult();
// ASSERT
Assert.AreEqual(10, _context.Users.CountAsync().GetAwaiter().GetResult());
}
As you can see, the tests are using the same in memory db, which I really don't like. I also don't like the new UserRepository(_context, logger). Is it a bad practice to use the new-keyword like this?
I would prefer something like this instead:
[Test]
public void Test1()
{
// Setup
var provider = RegisterServices();
var logger = _fixture.Freeze<ILogger<UserRepository>>();
var userRepo = provider.GetRequiredService<IUserRepository>();
var userViews = new List<UserView>();
userViews.AddRange(_fixture.CreateMany<UserView>(10));
// ACT
userRepo.UpdateUsers(userViews, CancellationToken.None).GetAwaiter().GetResult();
// ASSERT
Assert.AreEqual(10, _context.Users.CountAsync().GetAwaiter().GetResult());
}
private ServiceProvider RegisterServices([CallerMemberName] string memberName = "")
{
var services = new ServiceCollection();
services.AddDbContext<IDatabaseContext, DatabaseContext>(options =>
options.UseInMemoryDatabase(memberName));
services.AddPersistence("https://localhost");
return services.BuildServiceProvider();
}
As you can see, I have added a RegisterService method that takes the calling test as a parameter, and then uses this to create the inmemorydb. I really like this because you are isolating your tests more this way. I also think it's cleaner to read.
How would you guys do in this case? Is the first approach the way to go, or is my approach the more "right" way to do it? Or is it another better and more best practice way to do it?
I just want to know your opinions about this and about the two approaches above.