Skip to content

Instantly share code, notes, and snippets.

@jesslilly
Last active September 26, 2017 22:12
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jesslilly/d3ce6d776b0a3b0f35d8 to your computer and use it in GitHub Desktop.
Save jesslilly/d3ce6d776b0a3b0f35d8 to your computer and use it in GitHub Desktop.
Need to Mock a DbSet for testing Entity Framework? View the README.md file below.

I have used this code and it works well, but if you arre using DbFunctions, those are impossible to test with mocks. My suggestion is to use this where it makes sense, but know that you will not get complete code coverage especially if you use DbFunctions or Execute any SQL commands directly.

Another thing to consider is to not use the ORM for large transactions. For large selects, it's ok, but if you are doing any large updates, inserts or deletes, consider side-stepping the ORM and go for a more performant solution.

  1. You might need to implement GetHashCode (return an Id) and Equals (compare Id's) in order for the HashSet within InMemorySet to update properly.
  2. There are other things you may need to do to get testing with Moq to work with Entity Framework.
  3. I use NUnit instead of MS Testing Framework since NUnit has [TestCase()] (as of 6, 2015)
  4. Don't forget to use mock.Object.
  5. Don't forget to setup your mocks like this mockDb.Setup(x => x.Entities).Returns(entities); where entities is an InMemorySet<TEntity>();
  6. Using new Mock<TEntity> { CallBase = true }; is very handy such that you do not need to "Setup" all of the methods of the mocked object.
  7. mockEntity.SetupAllProperties(); is also convenient, such that you can assign to properties instead of calling "Setup().Returns".
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace FCM.Web.Tests.TestHelpers
{
/// <summary>
/// This is awesome. It's a class you can use to Mock a DbSet for
/// testing Entity Framework using mocks.
/// </summary>
/// <typeparam name="T"></typeparam>
class InMemorySet<T> : IDbSet<T> where T : class
{
private HashSet<T> _hashSet;
public InMemorySet()
{
_hashSet = new HashSet<T>();
}
public Expression Expression { get { return _hashSet.AsQueryable().Expression; } }
public Type ElementType { get { return _hashSet.AsQueryable().ElementType; } }
public IQueryProvider Provider { get { return _hashSet.AsQueryable().Provider; } }
public T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
public bool Contains(T entity)
{
return _hashSet.Contains(entity);
}
public T Add(T entity)
{
_hashSet.Add(entity);
return entity;
}
public void AddOrUpdate(params T[] entities)
{
foreach (var entity in entities)
{
AddOrUpdate(entity);
}
}
private void AddOrUpdate(T entity)
{
if (_hashSet.Contains(entity))
{
// Update behavior
_hashSet.Remove(entity);
}
_hashSet.Add(entity);
}
public T Remove(T entity)
{
_hashSet.Remove(entity);
return entity;
}
public T Attach(T entity)
{
_hashSet.Add(entity);
return entity;
}
public T Create()
{
throw new NotImplementedException();
}
public TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, T
{
throw new NotImplementedException();
}
public ObservableCollection<T> Local { get; private set; }
public IEnumerator<T> GetEnumerator()
{
return _hashSet.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _hashSet.GetEnumerator();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment