Unit Test for EF LINQ queries using Mocked DbSet

Goal: 
Create a unit test for a EF repository query. As we all know unit tests are infrastructure agnostic and therefore have no kowledge of for example external services, databases, etc. So how can we create a unit test for a repository query without hitting the DB? Mocked DbSet to the rescue:

Solution:
Create an extension method on collections that can be used to mock the data/collections returned by EF instead of hitting the DB.

//A List of allocations for a gas system that we want to return when the EF LINQ query is executed
var allocationVOMockDbSet = new List<AllocationVO>
{
new AllocationVO
{
LocationId = -1,
ContractId = -1,
NominationId = null,
AllocatedQuantity = 1000,
AdjustmentIndicatorType = AdjustmentIndicatorType.Measurement,
GasDayId = -100,
GasDay = new GasDay(null, DateTime.Today),
AccountingPeriod = new YearMonth(2016, 10)
},

//new
new AllocationVO
{
LocationId = -1,
ContractId = -1,
NominationId = null,
AllocatedQuantity = 1500,
AdjustmentIndicatorType = AdjustmentIndicatorType.Other,
GasDayId = -100,
GasDay = new GasDay(null, DateTime.Today),
AccountingPeriod = new YearMonth(2016, 10)
},
}
.AsMockDbSet();  //here we define the list as a mocked set

//Now we use the StructureMap container to create an inject the DbContext of IAfterFlowContext
var afterFlowContextMock = thisContainer.InstantiateAndInjectMock<IAfterFlowContext>();

//Now we add the setup for the mocked context on Set of AllocationVO (a domain entity) that returns the mocked set
afterFlowContextMock.Setup(s => s.Set<AllocationVO>()).Returns(allocationVOMockDbSet.Object);


//Here is the extension for collections on DbSet<T> that makes it possible to mock all the different implementations of the DbSet
public static Mock<DbSet<T>> AsMockDbSet<T>(this ICollection<T> source) where T : class
{
var queryable = source.AsQueryable();

var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator);
dbSet.Setup(s => s.Add(It.IsAny<T>())).Callback<T>(source.Add);
dbSet.Setup(s => s.Include(It.IsAny<string>())).Returns(dbSet.Object);
dbSet.Setup(x => x.AsNoTracking()).Returns(dbSet.Object);

return dbSet;
}



Print | posted @ Tuesday, January 30, 2018 8:11 AM

Comments on this entry:

Gravatar # Nice post
by Denver at 1/31/2018 4:58 AM

Awesome post. I Got some good idea by reading this topic. Great information thanks for sharing this post. - Data Cleansing Services Melbourne, Call Center Services Melbourne

http://leadgenerationservices.com.au/data-cleansing-and-list-building.html
Post A Comment
Title:
Name:
Email:
Comment:
Verification: