Oct 23, 2017 3:00 AM

Testing with the InMemory provider in Entity Framework

How to use the InMemory provider in Entity Framework Core to test your methods without hitting the database or using fakes and mocks

Kosta Kostov (CC0)

The InMemory database provider is an exciting feature in newer versions of Entity Framework, Microsoft’s open source ORM (object-relational mapper) framework for ADO.Net. Entity Framework simplifies data access in your .Net application by allowing you to write code to perform CRUD operations without interacting with the underlying database provider directly.

The InMemory data provider in Entity Framework makes life simpler by letting you test the code of your ASP.Net app against an in-memory database instead of having to install and configure the real thing. In this article we’ll examine how we can work with the InMemory provider in Entity Framework Core to write and execute unit tests for an ASP.Net Core application.

Note that the InMemory database provider is a general purpose database (not a relational database) designed strictly for the purposes of testing your application’s code. The supported platforms include the following:

  • .Net Framework 4.5.1 onwards
  • .Net Core
  • Mono 4.2.0 onwards
  • Universal Windows Platform

Entity Framework Core database providers

Basically, you can choose from three database providers for working with an in-memory database in Entity Framework Core. You will generally use either the Microsoft.EntityFrameworkCore.Relational package or the Microsoft.EntityFrameworkCore.InMemory package, depending on whether or not you need the relational database capabilities. The third option is the Microsoft.EntityFrameworkCore.Sqlite provider, if you want to use the lightweight SQLite database in an in-memory mode.

You can run the following command at the NuGet package manager console window to install the Entity Framework Core InMemory database provider in your project.

> Install-Package Microsoft.EntityFrameworkCore.InMemory

Create an ASP.Net Core application

Follow the steps outlined below to create a Web API project using ASP.Net Core in Visual Studio.

  1. Open Visual Studio 2017 
  2. Click File -> New -> Project
  3. In the New Project dialog window, select the “ASP.Net Core Web Application” project template
  4. Specify the name and location for your project and click OK
  5. In the “New ASP.Net Core Web Application” dialog window, select .Net Core and ASP.Net Core 2.0 (assuming that .Net Core 2.0 is installed in your system) from the two drop-down lists at the top of the dialog window
  6. Select “Web API” as the project template
  7. Ignore the “Enable Docker Support” checkbox—we won’t be needing it
  8. Ensure that the message “No Authentication” is displayed—we won’t be needing this either
  9. Click OK to save

A Web API project with the name you specified should now be visible in the Solution Explorer window. Next, create a Unit Test project in Visual Studio and save the project with a name. Then install the Microsoft.EntityFrameworkCore.InMemory package in both of these projects via NuGet.

Create an entity class and database context

Now, select your project in Solution Explorer window and create the following entity class named Author.

public class Author
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

The next thing you should do is create a custom DbContext class. Here is an example of a custom DbContext class named IDGDbContext.

public class IDGDbContext : DbContext
    {
        public IDGDbContext(DbContextOptions<IDGDbContext> options) : base(options)
        {
        }
        public DbSet<Author> Authors { get; set; }
    }

You can now create an instance of DbContextOptions<TContext> as shown below.

DbContextOptions<IDGDbContext> options;
var builder = new DbContextOptionsBuilder<IDGDbContext>();
builder.UseInMemoryDatabase();
options = builder.Options;

Next, you should pass this DbContextOptions instance to the constructor of the IDGDbContext class when instantiating it:

var context = new IDGDbContext(options);

If you are using SQL Server...

Note that if you are using SQL Server as the database, you can specify the following code in the ConfigureServices method.

services.AddDbContext<IDGDbContext>(options =>
            {
                options.UseSqlServer(Configuration
                [“ConnectionStrings:MyDBConnectionString”]);
            });

This assumes that you have a connection string defined with the name of MyDBConnectionString in your application configuration file. Anyway, since we are not using SQL Server as our database in this example, we will leave the discussion at that.

Write and execute unit tests against the in-memory database

Now you can write and execute your unit tests in much the same way as you write unit tests when using the DbContext class. The following code snippet illustrates a unit test method that validates whether insertion of data into an instance of the Author class is successful.

 [TestMethod]
        public void InsertDataTest()
        {  
            var author = new Author { Id = 1, FirstName ="Joydip", LastName ="Kanjilal" ;
            using (var context = new IDGDbContext(options))
            {
                context.Authors.Add(author);
                context.SaveChanges();
            }
            Author obj;
            using (var context = new IDGDbContext(options))
            {
               obj = context.Authors.FirstOrDefault(x => x.Id == author.Id);
            }
            Assert.AreEqual(author.FirstName, obj.FirstName);
        }

The following code listing shows the complete source code of the unit test class for your reference.

[TestClass]
    public class EFCoreInMemoryDemoTest
    {
        DbContextOptions<IDGDbContext> options;
        public EFCoreInMemoryDemoTest()
        {
            var builder = new DbContextOptionsBuilder<IDGDbContext>();
            builder.UseInMemoryDatabase();
            options = builder.Options;
        }

        [TestMethod]
        public void InsertDataTest()
        {  
            var author = new Author { Id = 1, FirstName ="Joydip", LastName ="Kanjilal" };
            using (var context = new IDGDbContext(options))
            {
                context.Authors.Add(author);
                context.SaveChanges();
            }
            Author obj;
            using (var context = new IDGDbContext(options))
            {
                obj = context.Authors.FirstOrDefault(x => x.Id == author.Id);
            }
            Assert.AreEqual(author.FirstName, obj.FirstName);
        }
    }

As you might expect, unit tests that leverage the InMemory data provider will run quite fast. Most importantly, you can now avoid creating fakes and mocks when writing your unit test methods.