mardi 27 octobre 2015

Mocking model collections in EntityFramework and Moq

I am playing around with an MVC web app hosted on Azure using Entity Framework and SQL Server. I'm trying to set it up for unit tests and I'm using Moq to mock the DbContext and having some issues down the line. I have the following models:

class Employee
{
   [Key]
   public int EmployeeID{get;set;}
   [ForeignKey("Business")]
   public int BusinessID {get;set;}
   public virtual Business {get;set;}
}
class Business
{
   public Business()
   {
      Employees = new HashSet<Employee>();
   }

   [Key]
   public int BusinessID{get;set;}
   public virtual ICollection<Employee> Employees{get;set;}
}

Such that I can iterate all the employees of a business as well as ask a particular employee who his employer is.

So when I get down to mocking the data for tests, I mock the DbContext:

var mockContext = Mock<MyDbContext>();

and I create some test set of data:

List<Business> businesses = new List<Business>();
Business business1 = new Business();
business1.Name = "TestBusiness"
...

Then mock the DbSet for Business (so MyDbContext.Businesses is non-null):

var queryableTestData = businesses.AsQueryable();
var mockSet = new Mock<DbSet<Business>();
mockSet.As<IDbSet<Business>>().Setup(m => m.Provider).Returns(queryableTestData.Provider);
mockSet.As<IDbSet<Business>>().Setup(m => m.Expression).Returns(queryableTestData.Expression);
mockSet.As<IDbSet<Business>>().Setup(m => m.ElementType).Returns(queryableTestData.ElementType);
mockSet.As<IDbSet<Business>>().Setup(m => m.GetEnumerator()).Returns( () => queryableTestData.GetEnumerator());
mockSet.As<IDbSet<Business>>().Setup(m => m.Local).Returns( mockSet.Object.Local );

And tie it into the mock DbContext:

mockContext.Setup(context => context.Businesses).Returns(mockSet.Object);
mockContext.Setup(context => context.Set<T>()).Returns(mockSet.Object);

And I do the same thing for creating some test employee data. The problem I face is that the Business.Employees collection always returns empty even though there might be data in the collections that would normally be populated during normal operation (ie some Employee with BusinessID == 1 exists and some Business with BusinessID == 1 exists, but Business.Employees is empty only while testing).

Do I have any options other than manually establishing all entity relationships (ie: business.Employees = myTestEmployeeList.Where(e => e.BusinessID == business.BusinessID); )? I imagine this approach would be unmanagable once the object relationships are non-trivial. I'm hoping I'm doing something wrong and someone can point out my error :) Thanks for your help and time!

Aucun commentaire:

Enregistrer un commentaire