Categories
.NET Programming

How to mock the DataContext (Entity Framework)

Earlier I wrote an article about how to mock the LINQ DataContext. I promised to write an article about how to do the same method with Entity Framework. It’s quite similar, but the only difference is creating an IDbContext interface and using DbSet<T>.

You can get the code from GitHub

The method

The main point is to create a Unit Of Work pattern that handles the context and keeps track of our repositories. The repository is then accessable through a Generic Repository pattern that specifies the same functions for all model classes, mocked or real.

Next we create a service layer which handles all business logic. It only contains IUnitOfWork interface, so with IoC / dependency injection we can inject either real or mocked UnitOfWork. The service layer doesn’t care what kind of data it is getting. It just talks to Unit Of Work which then delivers the data. This is so we can test our logic (service layer) in isolation. When you have many services that use the same Unit Of Work instance, you don’t have to worry about DataReader conflicts, because the Unit Of Work only makes a DataContext instance in the constructor, when an instance of UnitOfWork is created. So when dealing with many services, you only have one instance of the context. Unit Of Work handles that for us.

Student example

In this example I will use a model class named Student. Our Student model would look something like this:

public class Student
{
    public int id { get; set; }
    public string name { get; set; }
}

We start off by creating an interface for DbContext, called IDbContext, which our DataContext and MockDataContext will implement.

Here is theIDbContext interface:

public interface IDbContext
{
    DbSet<T> Set<T>() where T : class;
    DbEntityEntry<T> Entry<T>(T entity) where T : class;
    int SaveChanges();
    void Dispose();
}

Next I created an StudentDBContext class, which will inherit DbContext base class and implement IDbContext.

Here is the StudentDBContext class:

public partial class StudentDBContext : DbContext, IDbContext
{
    static StudentDBContext()
    {
        Database.SetInitializer<StudentDBContext>(null);
    }

    public StudentDBContext()
        : base(Name=StudentDBContext)
    {
    }

    public DbSet<Student> Students { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new StudentMap());
    }
}

Also the mapping class for the Student.

Here is the StudentMap class:

public class StudentMap : EntityTypeConfiguration<Student>
{
    public StudentMap()
    {
        // Primary Key
        this.HasKey(t => t.id);

        // Properties
        this.Property(t => t.name)
            .HasMaxLength(100);

        // Table & Column Mappings
        this.ToTable(Students);
        this.Property(t => t.id).HasColumnName(id);
        this.Property(t => t.name).HasColumnName(name);
    }
}

Generic Repository

I used a Generic Repository pattern to access my model classes. This is so I have generic actions for each model class (add/delete/update/getall, etc).

Here is my IRepository interface:

public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    void Add(T entity);
    void Delete(T entity);
    void DeleteAll(IEnumerable<T> entity);
    void Update(T entity);
    bool Any();
}

Next I created the Repository class that implements the interface. This class will work with AppDataContext, which is our EF DataContext. Later on we will also create a MockRepository that will handle our mocked data, but here is my Repository class:

public class Repository<T> : IRepository<T> where T : class
{
    private readonly IDbContext _context;
    private readonly IDbSet<T> _dbset;

    public Repository(IDbContext context)
    {
        _context = context;
        _dbset = context.Set<T>();
    }

    public virtual IQueryable<T> GetAll()
    {
        return _dbset;
    }

    public virtual void Add(T entity)
    {
        _dbset.Add(entity);
    }

    public virtual void Delete(T entity)
    {
        var entry = _context.Entry(entity);
        entry.State = EntityState.Deleted;
        _dbset.Remove(entity);
    }

    public virtual void DeleteAll(IEnumerable<T> entity)
    {
        foreach (var ent in entity)
        {
            var entry = _context.Entry(ent);
            entry.State = EntityState.Deleted;
            _dbset.Remove(ent);
        }
    }

    public virtual void Update(T entity)
    {
        var entry = _context.Entry(entity);
        _dbset.Attach(entity);
        entry.State = EntityState.Modified;
    }

    public virtual bool Any()
    {
        return _dbset.Any();
    }
}

Unit Of Work

Next step is to create the Unit Of Work. We start off by creating an interface that both our EF UnitOfWork and our MockUnitOfWork will implement.

Here is the IUnitOfWork interface:

public interface IUnitOfWork : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>() where TEntity : class;
    void Save();
}

Next we create a class that implements our interface. Again, this is the class that works with EF AppDataContext, not our mocked one.

Here is the UnitOfWork class:

public class UnitOfWork<TContext> : IUnitOfWork where TContext : IDbContext, new()
{
    private readonly IDbContext _ctx;
    private Dictionary<Type, object> _repositories;
    private bool _disposed;

    public UnitOfWork()
    {
        _ctx = new TContext();
        _repositories = new Dictionary<Type, object>();
        _disposed = false;
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        // Checks if the Dictionary Key contains the Model class
        if (_repositories.Keys.Contains(typeof(TEntity)))
        {
            // Return the repository for that Model class
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;
        }

        // If the repository for that Model class doesn't exist, create it
        var repository = new Repository<TEntity>(_ctx);

        // Add it to the dictionary
        _repositories.Add(typeof(TEntity), repository);

        return repository;
    }

    public void Save()
    {
        _ctx.SaveChanges();
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!this._disposed)
        {
            if (disposing)
            {
                _ctx.Dispose();
            }

            this._disposed = true;
        }
    }
}

Service layer

All of our business logic will be created in a service layer, because the controllers should not contain any logic. This is so all our logic can be in one place and that the same logic can be unit tested with mocked data.

So here is my StudentService class:

public class StudentService
{
    private IUnitOfWork _uow;

    private IRepository<Student> _Student;

    public StudentService(IUnitOfWork uow)
    {
        _uow = uow;

        _Student = _uow.GetRepository<Student>();
    }

    public IEnumerable<Student> GetAllStudents()
    {
        return _Student.GetAll();
    }

    public Student GetStudentByID(int id)
    {
        try
        {
            return _Student.GetAll().Where(s => s.id == id).SingleOrDefault();
        }
        catch (Exception ex)
        {
            throw new Exception(Failure getting student, ex);
        }
    }

    public void DeleteStudentByID(int id)
    {
        try
        {
            Student model = _Student.GetAll().Where(s => s.id == id).SingleOrDefault();
            _Student.Delete(model);
            _uow.Save();
        }
        catch (Exception ex)
        {
            throw new Exception(Failure deleting student, ex);
        }
    }
}

Mocking

Next we create a seperate implementation of our Repository and UnitOfWork classes, to work with mocked data. It’s a good practice to keep this in a seperate test project, in a namespace/folder called Mock or something like that.

Here is my MockRepository class:

public class MockRepository<T> : IRepository<T> where T : class
{
    public List<T> _context;

    public MockRepository(List<T> ctx)
    {
        _context = ctx;
    }

    public virtual IQueryable<T> GetAll()
    {
        return _context.AsQueryable();
    }

    public virtual void Add(T entity)
    {
        _context.Add(entity);
    }

    public virtual void Delete(T entity)
    {
        _context.Remove(entity);
    }

    public virtual void DeleteAll(IEnumerable<T> entity)
    {
        _context.RemoveAll(s => s == entity);
    }

    public virtual void Update(T entity)
    {
        var entry = _context.Where(s => s == entity).SingleOrDefault();
        entry = entity;
    }

    public virtual bool Any()
    {
        return _context.Any();
    }
}

Here is my MockUnitOfWork class:

public class MockUnitOfWork<T> : IUnitOfWork where T : class, new()
{
    private T _ctx;
    private Dictionary<Type, object> _repositories;

    public MockUnitOfWork()
    {
        _ctx = new T();
        _repositories = new Dictionary<Type, object>();
    }

    public IRepository<TEntity> GetRepository<TEntity>() where TEntity : class
    {
        if (_repositories.Keys.Contains(typeof(TEntity)))
        {
            return _repositories[typeof(TEntity)] as IRepository<TEntity>;
        }

        var entityName = typeof(TEntity).Name;
        var prop = _ctx.GetType().GetProperty(entityName);
        MockRepository<TEntity> repository = null;
        if (prop != null)
        {
            var entityValue = prop.GetValue(_ctx, null);
            repository = new MockRepository<TEntity>(entityValue as List<TEntity>);
        }
        else
        {
            repository = new MockRepository<TEntity>(new List<TEntity>());
        }
        _repositories.Add(typeof(TEntity), repository);
        return repository;
    }

    public void SetRepositoryData<TEntity>(List<TEntity> data) where TEntity : class
    {
        IRepository<TEntity> repo = GetRepository<TEntity>();

        var mockRepo = repo as MockRepository<TEntity>;
        if (mockRepo != null)
        {
            mockRepo._context = data;
        }
    }

    public void Save()
    {
    }

    public void Dispose()
    {
    }
}

Unit Test

Next we create our unit tests against our service layer. The service layer doesn’t care where it gets the data from. All it knows it talks to Unit Of Work that provides the data. This is so the logic can be unit tested in isolation. But first we need to implement our mocked AppDataContext with our fake data.

Here is the MockDataContext class:

public class MockDataContext
{
    public List<Student> Student
    {
        get
        {
            return new List<Student>
        {
            new Student
            {
                id = 1,
                name = John Doe,
            },
            new Student
            {
                id = 2,
                name = Victor Sagev,
            },
            new Student
            {
                id = 3,
                name = Wayne Johnson,
            }
        };
        }
    }
}

I created an example StudentServiceTest that tests all functions in the StudentService class. For this I use VisualStudio UnitTest library (Microsoft.VisualStudio.TestTools.UnitTesting).

Here is the StudentServiceTest class:

[TestClass]
public class StudentServiceTest
{
    IUnitOfWork _uow;
    StudentService _studentService;

    [TestInitialize]
    public void SetUp()
    {
        _uow = new MockUnitOfWork<MockDataContext>();
        _studentService = new StudentService(_uow);
    }

    [TestCleanup]
    public void TearDown()
    {
        // Clean resources
    }

    [TestMethod]
    public void TestGetStudentJohnDoe()
    {
        var student = _studentService.GetStudentByID(1);
        Assert.AreEqual(student.name, John Doe);
    }

    [TestMethod]
    public void TestDeleteStudentJohnDoe()
    {
        try
        {
            _studentService.DeleteStudentByID(1);
        }
        catch(Exception ex)
        {
            Assert.Fail(Expected no exception, but got:  + ex.Message);
        }
    }
}

So here we go. This is my method of creating a mocked testable service layer with mocked/real DataContext, using Unit Of Work and Generic Repository pattern.

20 replies on “How to mock the DataContext (Entity Framework)”

An impressive share, I just given this onto a colleague who was doing a little analysis on this. And he in fact bought me breakfast because I found it for him.. smile. So let me reword that: Thnx for the treat! But yeah Thnkx for spending the time to discuss this, I feel strongly about it and love reading more on this topic. If possible, as you become expertise, would you mind updating your blog with more details? It is highly helpful for me. Big thumb up for this blog post!

@muhammad Thank you so much. Yes I will in the future update the blog post with more details. ๐Ÿ™‚

@angela Thank you for your kind words. ๐Ÿ™‚

Wow thanks, really nice implementation.
I would like to modify the generic repository to make store procedure calls.
how would you do it?

In the GetRepository function the UnitOfWork implementation, I am getting an error on this line :

return _repositories[typeof(TEntity)] as IRepository;

Error:
The type ‘TEntity’ cannot be used as a type parameter ‘T’ in the generic type or method ‘blah.IRepository’. There is no implicit reference conversion from ‘TEntity’ to ‘System.IDisposable’

Might you have an idea what the root of this problem may be? It seems as if it might be a reference issue… would there be an issue referencing EF4 vs EF5?

Would it be too much to ask if you could recompile the project using .NET 4.0 and EF4? Unfortunately, I work in an environment that is not conducive to present-day technologies.

gauiis, thanks for such great tutorial. Can you please explain me why do you implement a Mock yourself instead of using “moq”. I mean some logic (UiW and Reps) is re-written and is not testable. Maybe i miss something. Thanks again for probably the best tutorial for both of patterns in use.

@evgenykhaliper:disqus

I agree with you.

What’s the purpose of creating a Mock and Mock? What benefit do we have when doing TDD? But thanks a lot for the nice tutorial.

Great post, was running into a brick wall with the regular FakeDbSet and FakeDbContext from romiller.com while trying to test against my generic Repository and UnitOfWork. I could not upgrade to EF6 and EF5 does not contain the default constructor DbSet().
Your solution paved the way to implementing my controller tests while still keeping everything generic. Thanks!

What about using services with WCF ? (as the ms recommended approach).
Do you have an example of your approach with WCF services where the service tier does not belong to the same physical server ?

I don’t have an example but that’s a whole different thing, because the repository would be on the WCF side so I would set up UnitOfWork there. But regarding testing, I would just abstract the WCF service, create a interface with two implementations; one that talks to the WCF service and one that talks to a mock repository. Then you can test the service interface (with mock data).

Entity Framework contains T4 templates that can generate C# classes for database entities. However, these T4 templates donโ€™t generate separated interfaces for the generated classes. This makes it difficult (if not impossible) to apply IoC and unit testing techniques.

Fortunately, you can now use Entity Interface Generator from https://entityinterfacegenerator.codeplex.com/

This project contains customized T4 templates which can generate interfaces and attributes for the DbContext class and entity classes.

nice post

Looking at your implementation of UoW, in the controller you’re hardcoding the StudentDBContext which makes it untestable, no? I know you’re doing the testing at the Service layer but still… Plus your web project has a dependency on EF (due to DBContext) which it really shouldn’t if you’re splitting your logic across multiple projects.

my 0.02

Leave a Reply

Your email address will not be published. Required fields are marked *