Unit Testing with Entity Framework Core 3
This post covers the basic structure for unit tests with Entity Framework Core.
Note: Unit tests are only there to test the respective logic. Unit tests do not replace integration tests, especially for database operations.
Install EFCore In-Memory Provider
EFCore comes with its own InMemory Provider, which is explicitly intended for testing and not for production: Microsoft.EntityFrameworkCore.InMemory
Conveniently, NuGet offers the possibility to simply copy the necessary package reference as an XML entry in order to paste it directly into the project file:
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
Setup Test Database Context
The goal is that each test has its own virtual, In-Memory database to enable real isolation in the tests.
I simply use a Guid, which acts as database name. This means that each test can run in parallel, as each test gets its own database and thus its isolated infrastructure.
// Setup Options
string dbName = Guid.NewGuid().ToString();
DbContextOptions<MyDbContext> options = new DbContextOptionsBuilder<MyDbContext>()
.UseInMemoryDatabase(databaseName: dbName).Options;
The database options can now be used in a test to build the respective context.
using (MyDbContext dbContext = new MyDbContext(options))
{
// your database stuff
}
Sample Test
It is generally recommended that adding and querying values in tests be done in different contexts.
Here is a complete example of an EF Core Test
- Connection establishment
- Adding values
- Querying values
[Fact]
public async Task User_Should_Be_Added()
{
// Setup
string dbName = Guid.NewGuid().ToString();
DbContextOptions<MyDbContext> options = new DbContextOptionsBuilder<MyDbContext>()
.UseInMemoryDatabase(databaseName: dbName).Options;
// Seed
using (MyDbContext dbContext = new MyDbContext(options))
{
PersonEntity person = PersonEntity.Create(1, "Batman", "Gotham City");
await dbContext.Persons.AddAsync(person);
await dbContext.SaveChangesAsync();
}
// Verify if insert works
using (MyDbContext dbContext = new MyDbContext(options))
{
PersonEntity person = await dbContext.Persons.SingleAsync(x => x.Id == 1);
// verify reference
person.Should().NotBe(null);
// verify properties
person.Id.Should().Be(1);
person.Name.Should().Be("Batman");
person.City.Should().Be("Gotham City");
}
}
In the case of a repository test, this code could be used almost 1:1.
Better Testing
For easier, better tests I recommend using the following libraries:
- XUnit - Test Framework
- FluentAssertions - Extension Methods for naturally assertions (like
.Should()
methods) - Moq - Best .NET mocking framework
- AutoFixture - injects values to test methods
- AutoFixture.AutoMoq - injects mocks to test methods
- AutoFixture.Xunit2 - Extensions for XUnit
- AutoFixture.SeedExtensions - great extensions for specific autofixture operations