Faking with In Memory Database In ASP.NET Core 2.0

Alright, I messed up between the terms: faking and mocking when one of my friend asked me "How are you faking in .net core?". I told him with my little to no knowledge about faking that, "Use the Moq library". But later found that I was totally wrong. And mocking is not actually faking. Then I read a lot of articles/blogs on those topics and came across with this beautiful blog post by Martin Fowler on Mocks Aren't Stubs. Take your time and read it to get your facts straight like me.

Quoting from Martin Fowler's blog post:

Fake: objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).

Mock: objects pre-programmed with expectations which form a specification of the calls they are expected to receive.

Fakes and Mocks both are test doubles. While fakes insist on state verification, mocks are for behavior verification.

All the terms like test double, state verification, behavior verification are well described in Martin Fowler's blog post.

So, how do you do fake testing in .net core then? One of the nicest feature available in Entity Framework Core (also available in EF 6.1 and later) is that it has a support for In-Memory database. Before this feature you would have fake the database/tables by faking the DbSet(s) of your entities. It is still possible to fake the DBSet if you want. But unlike in the earlier versions of Entity Framework (maybe before EF 6) there is no such interface like IDbSet<> in the newer versions. So, if you really want to fake a DbSet use the abstract class (DbSet<>) itself and override the methods of your choice. By the way I'm not going with that process here.

In my demo project, I have this ApplicationDbContext which basically contains a single DbSet called Geeks:

ApplicationDbContext.cs

public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {

    }
    public DbSet<Geek> Geeks { get; set; }
}

Notice the DbContextOptions parameter. The options are being filled out via dependency injection (ConfigureServices) in the Startup.cs file:

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}

Basically, the code wires up the ApplicationDbContext with an Sql server instance. Following is the appsettings.json file where a production level connection string is provided as the value against the DefaultConnection key.

appsettings.json

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=(localdb)\\MSSQLLocalDB;Database=MINF_DB;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

The idea is to unit test different methods of the repository. So, here goes the actual implementation:

Repository.cs

public class Repository : IRepository
{
    private readonly ApplicationDbContext _context;

    public Repository(ApplicationDbContext context)
    {
        _context = context;
    }

    public void Add(Geek geek)
    {
        _context.Geeks.Add(geek);
    }

    public IQueryable<Geek> Get()
    {
        return _context.Geeks;
    }

    public IQueryable<Geek> GetExpertGeeks()
    {
        return _context.Geeks.Where(g => g.Rating >= 3.5M);
    }

    public int SaveChanges()
    {
        return _context.SaveChanges();
    }
}

You can download the source code to see how the IRepository is laid out and configured to serve a new instance of Repository again in the ConfigureServices() method of Startup.cs.

Now you don't want to unit test against the actual SQL database rather you would use an In-Memory database. For the testing purpose, I've created a xUnit project and added the following package to enable In-Memory database support in EF Core:

Following would be a basic test case to unit test the GetExpertGeeks method of the Repository.

GeekRepositoryTest.cs

public class GeekRepositoryTest
{
    [Fact]
    public void GetExpertGeeks()
    {
        var builder = new DbContextOptionsBuilder<ApplicationDbContext>();
        builder.UseInMemoryDatabase();
        var options = builder.Options;

        using (var context = new ApplicationDbContext(options))
        {
            var geeks = new List<Geek>
            {
                new Geek { Id= 1, Name = "Tanzim Saqib", Expertise = "Machine Learning", Rating = 4},
                new Geek { Id= 2, Name = "Fiyaz Hasan", Expertise = "ASP.NET Core", Rating = 3.52M },
                new Geek { Id= 3, Name = "Jon Doe", Expertise = "Python", Rating = 3 },
                new Geek { Id= 4, Name = "Jane DOe", Expertise = "Data Science", Rating = 2.52M }
            };

            context.AddRange(geeks);
            context.SaveChanges();
        }

        using (var context = new ApplicationDbContext(options))
        {
            var repository = new Repository(context);
            var expertGeeks = repository.GetExpertGeeks();
            Assert.Equal(2, expertGeeks.Count());
        }
    }
}

Notice that I'm now creating a new instance of the DbContextOptionsBuilder. And while using the builder pattern to build the options for ApplicationDbContext, I'm telling it to use an in-memory database instance. Now, I'm good to go with faking a database instead of using a real one. That is how simple it is.

On a side note: In-memory database uses Linq to Object instead of Linq to Entity. Following are the links if you want to know which technique provides what facilities:

Demo Project Repository: https://github.com/fiyazbinhasan/FakingIsNotMocking