在 EntityFramework 和 Moq 中模拟模型集合

Mocking model collections in EntityFramework and Moq

我正在使用 Entity Framework 和 SQL 服务器在 Azure 上托管一个 MVC 网络应用程序。我正在尝试为单元测试设置它,我正在使用 Moq 来模拟 DbContext 并遇到一些问题。我有以下型号:

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;}
}

这样我就可以遍历一家企业的所有员工,并询问特定员工他的雇主是谁。

因此,当我开始模拟测试数据时,我模拟了 DbContext:

var mockContext = Mock<MyDbContext>();

我创建了一些测试数据集:

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

然后模拟 DbSet for Business(所以 MyDbContext.Businesses 是非空的):

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 );

并将其绑定到模拟 DbContext 中:

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

我做同样的事情来创建一些测试员工数据。我面临的问题是 Business.Employees 集合总是 returns 空,即使集合中可能存在通常在正常操作期间填充的数据(即存在一些 BusinessID == 1 的 Employee 和一些 Business BusinessID == 1 存在,但 Business.Employees 仅在测试时为空)。

除了手动建立所有实体关系(即:business.Employees = myTestEmployeeList.Where(e => e.BusinessID == business.BusinessID);)之外,我还有其他选择吗?我想一旦对象关系非常重要,这种方法将难以管理。我希望我做错了什么,有人可以指出我的错误 :) 感谢您的帮助和时间!

这是一个经典问题。我想你有两个选择。

  1. 处理它并根据需要手动设置关系
  2. 与其尝试模拟数据库,不如使用 SQLLite 作为测试的后端,entity framework 可以在此基础上发挥它的魔力。

2 的缺点是它可以为额外的设置和配置问题增加大量的执行时间,这会弹出并咬你的屁股。

我个人更喜欢选项 1。