Introduction
EntityFramework.MoqHelper
is a simple library, but a lot of help when it comes to mock with Entity Framework.
To create objects through mock, it needs to perform many settings, especially for test scenarios where queries are made.
Many of these codes required were encapsulated in that library and some logic to work with lists of objects and queries were made. Using a fluent interface, you can perform different settings to mock DbContext
and DbSet
objects.
To mock EF objects, the library was chosen to Moq (https://github.com/Moq/moq4) because it is a stable and very popular library of Mock in general.
The focus of this library is to facilitate the developer's life when testing using EF without accessing the database directly.
Background
In Entity Framework 6, many improvements have been made, including test scenarios, it is now possible to make mock of the main methods used for reading and writing to the database.
To understand in more detail what it was and how it was improved with focus on mocks suggest a reading of the post of Julie Lerman "How EF6 Enables Mocking DbSets more easily" which can be accessed below:
For a more practical view, I suggest reading the post "Testing with a mocking framework (EF6 onwards)", is also important for those who are not yet familiar with mocks the EF.
Using the Code
This is a simple query scenario, taken from one of the references cited in the "Background" section important to understand how the mock and the settings are made on DbContext
and DbSet
objects.
[TestClass]
public class QueryTests
{
[TestMethod]
public void GetAllBlogs_orders_by_name()
{
var data = new List<Blog>
{
new Blog { Name = "BBB" },
new Blog { Name = "ZZZ" },
new Blog { Name = "AAA" },
}.AsQueryable();
var mockSet = new Mock<DbSet<Blog>>();
mockSet.As<IQueryable<Blog>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<Blog>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<Blog>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<Blog>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<BloggingContext>();
mockContext.Setup(c => c.Blogs).Returns(mockSet.Object);
var service = new BlogService(mockContext.Object);
var blogs = service.GetAllBlogs();
Assert.AreEqual(3, blogs.Count);
Assert.AreEqual("AAA", blogs[0].Name);
Assert.AreEqual("BBB", blogs[1].Name);
Assert.AreEqual("ZZZ", blogs[2].Name);
}
}
Pay attention to required settings that are made in the implementation of IQueryable
and DbSet
(the mock settings related to the class being tested) and in the application DbContext.
All of this code is still necessary and they were encapsulated using fluent interface. The code listed above is a lot verbose, in this method we have more code referent to settings the mock instead of business rules that were tested and things only gets worse when we add in this scenario inserts, updates and deletions of items.
You must configure each Entity Framework method related to each operation you want to make the database available in DbSet
as DbSet.Add
, DbSet.Find
and DbSet.Remove
, for example.
Using this library, it can make it through something like:
var customers = new List<Customer>();
var mockSet = EntityFrameworkMoqHelper.CreateMockForDbSet<Customer>()
.SetupForQueryOn(customers)
.WithAdd(customers, "CustomerID")
.WithFind(customers, "CustomerID")
.WithRemove(customers);
To see a more complex sample of how to use this library, you can take a look at my project on github referenced below:
To install as nuget package, run the following command in the Package Manager Console:
Install-Package EntityFramework.MoqHelper