在 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);
)之外,我还有其他选择吗?我想一旦对象关系非常重要,这种方法将难以管理。我希望我做错了什么,有人可以指出我的错误 :) 感谢您的帮助和时间!
这是一个经典问题。我想你有两个选择。
- 处理它并根据需要手动设置关系
- 与其尝试模拟数据库,不如使用 SQLLite 作为测试的后端,entity framework 可以在此基础上发挥它的魔力。
2 的缺点是它可以为额外的设置和配置问题增加大量的执行时间,这会弹出并咬你的屁股。
我个人更喜欢选项 1。
我正在使用 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);
)之外,我还有其他选择吗?我想一旦对象关系非常重要,这种方法将难以管理。我希望我做错了什么,有人可以指出我的错误 :) 感谢您的帮助和时间!
这是一个经典问题。我想你有两个选择。
- 处理它并根据需要手动设置关系
- 与其尝试模拟数据库,不如使用 SQLLite 作为测试的后端,entity framework 可以在此基础上发挥它的魔力。
2 的缺点是它可以为额外的设置和配置问题增加大量的执行时间,这会弹出并咬你的屁股。
我个人更喜欢选项 1。