How to unit test a repository pattern that uses Entity Framework?

c# entity-framework repository-pattern unit-testing

Question

I'm currently trying to unit test a repository I made through Entity Framework:

What I want to happen is that test the repository without actually sending/connecting to the actual database, I want to this without using any mocking framework.

Currently my test is sending the data to the database, what I want to happen is test the add/remove etc. methods without sending the actual data to the database since it's only for testing.

Here is the repository:

namespace AbstractFactory.Repository
{
    using System.Collections.Generic;
    using System.Data.Entity;
    using System.Linq;

    /// <summary>
    /// This class serves as the structure of the Author repository using a database
    /// </summary>
    public class DbAuthorRepository : IRepository<AuthorEntity>
    {

        private AbstractFactoryPatternEntities context;

        public DbAuthorRepository(AbstractFactoryPatternEntities context)
        {
            this.context = context;
        }

        /// <summary>
        /// Adds the specified author.
        /// </summary>
        /// <param name="author">The author.</param>
        public void Add(AuthorEntity author)
        {
            context.AuthorEntities.Add(author);
        }

        /// <summary>
        /// Removes the specified author.
        /// </summary>
        /// <param name="author">The author.</param>
        public void Remove(AuthorEntity author)
        {
            this.context.AuthorEntities.Remove(author);
        }

        /// <summary>
        /// Saves this instance.
        /// </summary>
        public void Save()
        {
            this.context.SaveChanges();
        }

        /// <summary>
        /// Gets all.
        /// </summary>
        /// <returns>returns a list of all the authors</returns>
        public IEnumerable<AuthorEntity> GetAll()
        {
            List<AuthorEntity> result = this.context.AuthorEntities.Include(a => a.Books).ToList();

            return result;
        }

        /// <summary>
        /// Gets the author by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <returns>returns an entity</returns>
        public AuthorEntity GetById(int id)
        {
            AuthorEntity result = this.context.AuthorEntities.Single(a => a.AuthorId == id);

            return result;
        }
    }
}

Here is the current code for the unit test:

[TestMethod]
        public void Add_MethodIsCalled_EntityCountIsIncrementedByOne()
        {
            using (ShimsContext.Create())
            {
                ShimAbstractFactoryPatternEntities context = new ShimAbstractFactoryPatternEntities(new AbstractFactoryPatternEntities());
                DbAuthorRepository repository = new DbAuthorRepository(context);
                repository.Add(new AuthorEntity { FirstName = "Test", LastName = "testing=" });
                var actual = repository.GetAll().Count();
                repository.Save();
                var expected = repository.GetAll().Count();
                Assert.AreNotEqual(actual, expected);
            }

            //AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            //DbAuthorRepository repository = new DbAuthorRepository(context);
            //var actual = repository.GetAll().Count();
            //repository.Add(new AuthorEntity { FirstName = "Testing", LastName = "MyTest" });
            //repository.Save();
            //var expected = repository.GetAll().Count();
            //Assert.AreNotEqual(actual, expected);
        }

        [TestMethod]
        public void Remove_MethodIsCalled_EntityCountRemainsTheSame()
        {
            AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            DbAuthorRepository repository = new DbAuthorRepository(context);
            AuthorEntity newAuthor = new AuthorEntity { FirstName = "Testing", LastName = "MyTest" };
            repository.Add(newAuthor);
            repository.Save();
            var actual = repository.GetAll().Count();
            Console.WriteLine(actual);
            repository.Remove(newAuthor);
            var expected = repository.GetAll().Count();
            Console.WriteLine(expected);
            Assert.AreEqual(actual, expected);
        }

        [TestMethod]
        public void Get_MethodIsCalled_CorrectAuthorIsRetrieved()
        {
            AbstractFactoryPatternEntities context = new AbstractFactoryPatternEntities();
            DbAuthorRepository repository = new DbAuthorRepository(context);
            int target = 4;
            AuthorEntity author = repository.GetById(target);
            Assert.AreEqual(target, author.AuthorId);
        }

I want to use shims/stub/fakes in order to make the test.

1
16
4/3/2013 3:48:10 PM

Accepted Answer

The Entity Framework repository is a concrete implementation of your repository interface. Because it is concrete, you can't abstract it and test without the database - the whole point of this concrete implementation is to write the data to the database!

This means that testing EF repositories should rather aim at verifying that repositories write to actual database - in the act phase of your test you invoke repository methods and in the assert phase you use any other way of getting the data from the database (ado.net perhaps?) to check if the repository does its job.

Yet another, unrelated thing is that you can have another implementation of the repository which uses an in-memory data store and injecting such in-memory repository to other services allows you to test these services wihout writing to a physical database. You could even mock a repository injected to other services just to perform some behavioral tests, i.e. test whether your services use your repositories correctly.

17
4/3/2013 3:48:30 PM

Popular Answer

You can replace connection to your database with in-memory DB, such as Effort. Then you can test your repository logic. In more details can be found here



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow