18

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.

Randel Ramirez
  • 3,671
  • 20
  • 49
  • 63
  • 1
    If all that your repositories are doing is one line of code that is making a call to EF then you don't need to do any form of unit testing at all on it. Even Uncle Bob agrees: http://blog.8thlight.com/uncle-bob/2013/03/06/ThePragmaticsOfTDD.html – Corey Adler Apr 03 '13 at 15:20
  • + 1 to @IronMan84 - dont bother testing any framework, else you could potentially find yourself testing code that you can't fix. – Srikanth Venugopalan Apr 03 '13 at 15:34
  • @GertArnold What I want to happen is that test the repository without actually sending/connecting to the actual database – Randel Ramirez Apr 03 '13 at 15:46
  • @randelramirez1 You tell what you want, but you don't _ask_ anything. I don't know what to answer. And then, you don't want to mock, so what do you want to fake? – Gert Arnold Apr 03 '13 at 17:33

2 Answers2

22

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.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
  • 7
    +1 Too many people try to mock something that can't be mocked. I collected some evidence [here](http://stackoverflow.com/a/13352779/861716). – Gert Arnold Apr 03 '13 at 17:36
  • @GertArnold: impressive evidence. – Wiktor Zychla Apr 03 '13 at 20:02
  • 1
    If I understand, you're saying that we should create another data access implementation (using ado.net) to verify that EF works. Doesn't this add a lot of overhead? – betitall Oct 09 '13 at 03:53
  • @betitall: it probably is but is there in your opinion any other way to verify that the EF repository is doing its job? I've seen tests where people use the same repository to write data and then read and compare results. This doesn't unfortunately test anything other than the correspondence between reads and writes. It is still unknown after such test whether the data go to actual database or not. – Wiktor Zychla Oct 09 '13 at 06:52
8

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

druss
  • 1,820
  • 19
  • 18