How do you unit test something that has a dependency on Entity Framework? I ran into a situation recently when the code I wanted to test was loading a set of rules from a database that dictated the what functionality a web site had.
This is one of the those blogs most that is more of a reminder for me on how to do it. So it’s a message from past me to future, but hopefully it will help out someone else as well.
One way to test a database, which I wouldn’t advise, it to had a test database with a know state of data which you can test against. You simply swap out the connection string to test against the test data. There are a number of issue with this:
- You have to pre-load the data with database. This can become complicated, prone to error and slow.
- If you have multiple instances or developers of the tests at once, the data may be updated by one test instance, which inadvertently breaks another test.
- Different tests will likely need different data setup.
In memory database to the rescue…
A much easier way is to use an in memory database to mock the data. Entity Framework makes this very easy. You simply instantiate the data context to use an in memory database (instead of a SQL one) and then you can load data into using your code. This means you only need to load the data that is specific to the test you are running, and the data is just for that test and won’t be changed by any other tests.
You can use the standard Entity Framework methods to add the data, e.g. Add(Entity) and SaveChanges().
Here’s an example:
using Microsoft.EntityFrameworkCore;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
namespace InMemoryDatabaseTest
{
[TestClass]
public class CompanyTest
{
DBContext _inMemoryContext;
ICompanyHelper _companyHelper;
[TestInitialize]
public void TestInitialize()
{
//Initalise the in memory database. This uses the same Data
//context I have already setup for my project, but has a different //configuration so that it uses an in memory database.
var options = new DbContextOptionsBuilder<DBContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
_inMemoryContext = new DBContext(options);
//The Class to be tested, which has a dependency on the data context
_companyHelper = new CompanyHelper(_inMemoryContext);
}
[TestMethod]
public void CompanyHierarchyTest()
{
//Set up data in the in memory database.
//This is done in the same way as adding data to EF: First add
//the object, then call SaveChanges() on the context
Company company1 = new Company()
{
ID = 1,
Created = DateTime.Now,
CreatedBy = Guid.NewGuid().ToString(),
Name = “Company 1”,
ParentID = 0
};
_inMemoryContext.Companies.Add(company1);
Company company2 = new Company()
{
ID = 2,
Created = DateTime.Now,
CreatedBy = Guid.NewGuid().ToString(),
Name = “Company 2”,
ParentID = 1
};
_inMemoryContext.Companies.Add(company2);
_inMemoryContext.SaveChanges();
//Call the class to be tested
var companyHierarchy = _companyHelper.GetCompanyHierarchy(company1);
//Test the assertion
var expectedCount = 2;
Assert.AreEqual(expectedCount, companyHierarchy.Count);
}
}
}
The data context has the following constructor:
public class DBContext : DbContext
{
public DBContext(DbContextOptions<DBContext> options) : base(options)
{
}
}