While unit-testing EF Core applications, sometimes, we may want to mock EF Core DbContext. In this article, we’ll talk about a few ways of doing that.

To download the source code for this article, you can visit our GitHub repository.

Let’s get going.

When to Mock EF Core DbContext

There are different ways in which we can test an application that uses the EF Core database. The first and foremost option is to test it against an actual production database. This ensures that the application behaves as expected in production as well. However, it is not always feasible to test an application with an actual production database. This brings us to the next option – testing our application using some fake data.

Support Code Maze on Patreon to get rid of ads and get the best discounts on our products!
Become a patron at Patreon!

If we are planning to use fake test data, then the best option is to implement a repository pattern and mock the data access layer. By implementing this, we can have a clear separation between the data access layer and the business logic of our application. Apart from that, we can easily test our application as well using this pattern.

However, if implementing a repository pattern is not viable for an application, then we can think of either using a fake EF Core provider like SQLite, In-Memory, etc., or mocking the DbContext.

We are going to learn how to mock an EF Core DbContext by using two popular libraries:

  • Moq.EntityFrameworkCore
  • MockQueryable

Without further ado, let’s start.

Preparing the Environment

First, let’s configure an EF Core application.

As explained in the linked article, let’s create an Employee model for this example:

public class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public string Phone { get; set; }
}

After creating the context file and updating the database, let’s create a controller with two action methods:

public class EmployeesController : ControllerBase
{
    private readonly EmployeeDBContext _context;

    public EmployeesController(EmployeeDBContext context)
    {
        _context = context;
    }

    // GET: api/Employees
    [HttpGet]
    public async Task<ActionResult<IEnumerable<Employee>>> GetEmployees()
    {
        return await _context.Employees.ToListAsync();
    }

    // GET: api/Employees/5
    [HttpGet("{id}")]
    public async Task<ActionResult<Employee>> GetEmployeeById(int id)
    {
        var employee = await _context.Employees.FindAsync(id);

        if (employee is null)
        {
            return NotFound();
        }

        return employee;
    }
}

Here we have the GetEmployees() method that returns all employee records and the GetEmployeeById() method that fetches the employee record with the specified Id.

Feel free to skip creating a repository layer in this example as our focus in this article is on mocking EF Core DbContext when implementing a repository pattern is not feasible.

How to Mock EF Core DbContext Using Moq.EntityFrameworkCore

Now, let’s take a look at how to mock EF Core DbContext using the Moq.EntityFrameworkCore library. For that, let’s install the Moq.EntityFrameworkCore NuGet package:

Install-Package Moq.EntityFrameworkCore

This library will help us to mock EF Core contexts and we can test methods that are using the DbContext, DbSet, etc.

We can reference the library by including the Moq.EntityFrameworkCore namespace:

using Moq.EntityFrameworkCore;

Now, let’s write a test for the GetEmployees() method:

[Fact]
public async Task GetEmployees_WhenCalled_ReturnsEmployeeListAsync()
{
    // Arrange
    var employeeContextMock = new Mock<EmployeeDBContext>();
    employeeContextMock.Setup<DbSet<Employee>>(x => x.Employees)
        .ReturnsDbSet(TestDataHelper.GetFakeEmployeeList());

    //Act
    EmployeesController employeesController = new(employeeContextMock.Object);
    var employees = (await employeesController.GetEmployees()).Value;

    //Assert
    Assert.NotNull(employees);
    Assert.Equal(2, employees.Count());
}

Here we mock the DbContext and set up the Employee DbSet to return a fake employee list:

private static List<Employee> GetFakeEmployeeList()
{
    return new List<Employee>()
    {
        new Employee
        {
            Id = 1,
            Name = "John Doe",
            Email = "[email protected]",
            Phone = "123-456-7890"
        },
        new Employee
        {
            Id = 2,
            Name = "Mark Luther",
            Email = "[email protected]",
            Phone = "123-456-7890"
        }
    };
}

Now, what about testing the GetEmployeeById() method? This method uses the DbSet.FindAsync() method for fetching an employee record and we need to mock that method. But Moq.EntityFrameworkCore doesn’t provide any inbuilt way of mocking the FindAsync() method. However, the good news is that we can still test this by mocking the DbContext and setting up the FindAsync() method:

[Fact]
public async Task GetEmployeeById_WhenCalled_ReturnsEmployeeAsync()
{
    // Arrange            
    var employeeContextMock = new Mock<EmployeeDBContext>();
    employeeContextMock.Setup(x => x.Employees.FindAsync(1).Result)
        .Returns(TestDataHelper.GetFakeEmployeeList().Find(e => e.Id == 1) ?? new Employee());

    //Act
    EmployeesController employeesController = new(employeeContextMock.Object);
    var employee = (await employeesController.GetEmployeeById(1)).Value;

    //Assert
    Assert.NotNull(employee);
    Assert.Equal(1, employee.Id);
}

Here we mock the DbContext and set up the FindAsync() method of the DbSet to return a particular employee record when we pass a particular Id. Using this, we can test the GetEmployeeById() method.

How to Mock EF Core DbContext Using MockQueryable

The MockQueryable library provides extensions for mocking EF Core operations like ToListAsync(), FindAsync(), etc. It works pretty well with mocking libraries like Moq, NSubstitute, and FakeItEasy. Now let’s see how to mock EF Core DbContext using the MockQueryable library for the same example.

For using MockQueryable, first, we need to install the NuGet package corresponding to the mocking library that we use. Since we are using Moq, let’s install MockQueryable.Moq package:

Install-Package MockQueryable.Moq

Similarly, if we are using NSubstitute, we can use the MockQueryable.NSubstitute package and with FakeItEasy, we can use the MockQueryable.FakeItEasy package.

After that, we can reference the library by including the specific namespace, in our case the MockQueryable.Moq :

using MockQueryable.Moq;

Now, let’s write a test for the GetEmployees() method:

[Fact]
public async Task GetEmployees_WhenCalled_ReturnsEmployeeListAsync()
{
    // Arrange
    var mock = TestDataHelper.GetFakeEmployeeList().BuildMock().BuildMockDbSet();
    var employeeContextMock = new Mock<EmployeeDBContext>();
    employeeContextMock.Setup(x => x.Employees).Returns(mock.Object);

    //Act
    EmployeesController employeesController = new(employeeContextMock.Object);
    var employees = (await employeesController.GetEmployees()).Value;

    //Assert
    Assert.NotNull(employees);
    Assert.Equal(2, employees.Count());
}

Here, first, we build a mock DbSet using the fake employee list. After that, we set up the DbContext to return this DbSet. This way, we can test the GetEmployees() method by using a mock DbSet.

Next, we are going to test the GetEmployeeById() method. As we mentioned earlier, this method uses the DbSet.FindAsync() method for fetching a specific employee record. The good news here is that the MockQueryable library provides inbuilt support for mocking the FindAsync() method of the mock DbSet that we create. So let’s write a test by mocking the DbSet.FindAsync() method:

[Fact]
public async Task GetEmployeeById_WhenCalled_ReturnsEmployeeAsync()
{
    // Arrange
    var mock = TestDataHelper.GetFakeEmployeeList().BuildMock().BuildMockDbSet();
    mock.Setup(x => x.FindAsync(1)).ReturnsAsync(
        TestDataHelper.GetFakeEmployeeList().Find(e => e.Id == 1));

    var employeeContextMock = new Mock<EmployeeDBContext>();
    employeeContextMock.Setup(x => x.Employees)
        .Returns(mock.Object);

    //Act
    EmployeesController employeesController = new(employeeContextMock.Object);
    var employee = (await employeesController.GetEmployeeById(1)).Value;

    //Assert
    Assert.NotNull(employee);
    Assert.Equal(1, employee.Id);
}

Here, we create a mock DbSet and set up the FindAsync() method. Next, we set up a mock DbContext using this DbSet. Now since we have mocked the DbSet.FindAsync() method, we can easily test the GetEmployeeById() method.

Moq.EntityFrameworkCore vs MockQueryable

We use the Moq.EntityFrameworkCore for mocking EF Core contexts. By using it, we can easily test methods that are using the DbSet or DbQuery from the DbContext. However, this library supports only the Moq library for mocking. So if we are using Moq and we just want to mock a DbSet or DbQuery, then it makes perfect sense to use this library. On the other hand, if we want to use other mocking libraries like NSubstitute or FakeItEasy or if we want to mock EF Core query operations, then this library will not work.

MockQueryable provides extensions for mocking several EF Core operations such as FindAsync(), ToListAsync(), FirstOrDefaultAsync(), etc. It helps us in building a mock DbSet and then set up these EF Core methods inside it. This is very helpful in testing methods that implement EF Core query operations. Additionally, it supports different mocking libraries such as Moq, NSubstitute, and FakeItEasy. So if we are using any of these mocking libraries and want to test methods that implement various EF Core operations, then MockQueryable is a great choice.

Conclusion

In this article, we learned how to mock EF Core DbContext. We used two libraries Moq.EntityFrameworkCore and MockQueryable and saw how to write unit tests using those and which one to use in which scenario etc.

Liked it? Take a second to support Code Maze on Patreon and get the ad free reading experience!
Become a patron at Patreon!