How To Unit Test Entity Framework

If you want to learn how to easily write unit tests for entity framework, read on.  All your entity framework code will talk to a database, which under normal test conditions will fail.  Instead, to make your tests easy to write we want to hi-jack your entity framework context and point it to an in-memory store, rather than a database.

This might sounds complex, however, a great Nuget package exists, called 'EFFORT'.  EFFORT allows you to mock entity framework so you can test your entity code as expected.  In this guide, you will learn how to install and configure EFFORT.  I will also include a unit test to show you how easy it is to write tests.

How To Install EFFORT

You can install EFFORT (Entity Framework Fake ObjectContext Realization Tool), via Nuget

 

Make sure you use the correct version of EFFORT with the version of entity framework you are using.  I'm assuming you'll be using entity framework 6, so use the EFFORT.EF6 package.  If you use the wrong package, when you test your code it will throw a NotSupportedException Unable to determine the provider name for provider factory of type 'System.Data.EntityClient.EntityProviderFactory'.  Also remember, you only need to add effort to your unit testing project.  After installing EFFORT, next, it's time to configure it. 

How To Configure EFFORT

First, I'm assuming you have a unit test project within your solution with EFFORT installed. In your test project you need to create this class:

    public class EffortProviderFactory : IDbConnectionFactory
    {
        private static readonly object _lock = new object();

        private static DbConnection _connection;

        public static void ResetDb()
        {
            lock (_lock)
            {
                _connection = null;
            }
        }

        public DbConnection CreateConnection(string nameOrConnectionString)
        {
            lock (_lock)
            {
                if (_connection == null)
                {
                    _connection = Effort.DbConnectionFactory.CreateTransient();
                }

                return _connection;
            }
        }
    }

Next, you need to configure your application, so when you call entity instead of calling back to a database, it calls this factory and makes the request to memory instead.

In your app.config, you should have an entity framework section, you need to change the 'defaultconnectionfactory' setting.  That's the configuration done with, let's write some tests!

 

  <entityFramework>
    <defaultConnectionFactory type="JonDJones.Tests.EffortProviderFactory, JonDJones.Tests" />
    <providers>
      <provider invariantName="System.Data.SqlClient" type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer" />
    </providers>
  </entityFramework>

The only change I made from the default setting was changing the type. With this format -> your namespace.class name, Assembly Name.

Writing Tests With EFFORT

Now we can start writing tests:

    [TestFixture]
    public class MyClassTests
    {
        private MyClass _myClass;
        private MyContext _myContext;

        [OneTimeSetUp]
        public void TestFixtureSetUp()
        {
            Effort.Provider.EffortProviderConfiguration.RegisterProvider();
        }

        [SetUp]
        public void SetUp()
        {
            EffortProviderFactory.ResetDb();
            _myClass = new MyClass(_myContext.Object);
        }
        
        [Test]
        public void TestMyContext()
        {
            _myContext = new MyContext();
            _myContext.Entities.Add(new Entity { Name = "Node" });
            _myContext.SaveChanges();

            _sut.DeleteEntities();

            var result = _myContext.Entities.ToList();
            Assert.AreEqual(result.Count(), 0);
        }
    }

Let's step through the code above. First, we define a method with the OneTimeSetUp attribute. This registers the EFFORT provider. Next, in SetUp we ensure our data store is empty, by using the ResetDb() call.

In our test, we can then create a new instance of our context, write the set-up code. In this instance, adding a single item to the collection. Next, we need to save the result in memory. If you do not do this your context will be empty! Next, we run our test. My code simply deletes everything from the store. Without using EFFORT this would throw an exception. The code in case you care, looks similar to this:

  public void DeleteEntities()
  {
      _myContext.Entities.RemoveRange(_myContext.Entities);
  }
  

When I run this code, my test runs entity doesn't throw any exceptions, the entities get removed and I can write tests to prove it, simple!

submit to reddit

Jon D Jones

Software Architect, Programmer and Technologist Jon Jones is founder and CEO of London-based tech firm Digital Prompt. He has been working in the field for nearly a decade, specializing in new technologies and technical solution research in the web business. A passionate blogger by heart , speaker & consultant from England.. always on the hunt for the next challenge

Back to top