使用最小起订量模拟对 IQueryable 的调用
Mock a call to IQueryable using moq
我正在尝试最小化我拥有的存储库,该存储库定义为:
public IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null, bool disableTracking = true)
有没有办法模拟这个?我希望使用我提供回购协议的模拟数据执行查询。我不确定如何告诉最小起订量,当我调用 GetAll 时,我希望它仍然 运行 传入的查询,但它反对我提供的数据集。所以它不会进入数据库,而是针对我配置的模拟集。我能够创建数据,它包含 12 条记录,但我希望 getall moq 调用执行它的查询并将其过滤为应该返回的 2。
发生调用的实际服务是:
var list = await _unitOfWork.GetRepository<CASE_ACTIVITY>().GetAll(predicate: x => x.SM_SITE_ID == siteId && x.CMS_USER_ID == userId
&& x.IS_DELETED == "N" && x.Appointment.IS_DELETED == "N" && x.Appointment.IS_ARCHIVED == "N" && x.IS_ARCHIVED == "N"
&& ((x.Appointment.APPOINTMENT_DATETIME.HasValue && x.Appointment.APPOINTMENT_DATETIME.Value.Date == DateTime.Today.Date)
|| (!x.Appointment.APPOINTMENT_DATETIME.HasValue && x.ACTIVITY_STATUS_ID == _appSettings.CASE_ACTIVITY_STATUS_ID_PENDING)))
.Include(x => x.Activity_Lookup).Include(x => x.Appointment).ThenInclude(x => x.Cms_Client).Include(x => x.Cms_Case)
.ToListAsync();
假设您对 GetRepository()
方法有足够的控制权,可以使 it return 成为您的模拟存储库,模拟方法本身相当简单(如果有点冗长)。我只是将 GetAll
方法转储到一个名为 IRepository
的接口中,这就是模拟的样子。在 Returns
方法内部,您可以访问每个参数以根据需要执行或忽略。
var mock = new Moq.Mock<IRepository>();
mock.Setup(a => a.GetAll<int>(It.IsAny<Expression<Func<int, bool>>>(), It.IsAny<Func<IQueryable<int>, IOrderedQueryable<int>>>(), It.IsAny<Func<IQueryable<int>, IIncludableQueryable<int, object>>>(), It.IsAny<bool>()))
.Returns<Expression<Func<int, bool>>, Func<IQueryable<int>, IOrderedQueryable<int>>, Func<IQueryable<int>, IIncludableQueryable<int, object>>, bool>((param1, param2, param3, param4) =>
{
return new[] { 1, 2, 3 }.AsQueryable();
});
var result = mock.Object.GetAll<int>();
从这里开始,如果不查看更多代码,我们将无能为力。不过,从抽象的角度来说,您将获取 mock.Object
(属于 IRepository
类型)并将其提供给 GetRepository() 从中提取的任何集合。当然,还要注意,我使用了 int 作为通用参数——您可以将其替换为您正在使用的任何类型。可以制作一个接受通用参数的模拟,但希望这不是必需的!
我正在尝试最小化我拥有的存储库,该存储库定义为:
public IQueryable<TEntity> GetAll(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null, Func<IQueryable<TEntity>, IIncludableQueryable<TEntity, object>> include = null, bool disableTracking = true)
有没有办法模拟这个?我希望使用我提供回购协议的模拟数据执行查询。我不确定如何告诉最小起订量,当我调用 GetAll 时,我希望它仍然 运行 传入的查询,但它反对我提供的数据集。所以它不会进入数据库,而是针对我配置的模拟集。我能够创建数据,它包含 12 条记录,但我希望 getall moq 调用执行它的查询并将其过滤为应该返回的 2。
发生调用的实际服务是:
var list = await _unitOfWork.GetRepository<CASE_ACTIVITY>().GetAll(predicate: x => x.SM_SITE_ID == siteId && x.CMS_USER_ID == userId
&& x.IS_DELETED == "N" && x.Appointment.IS_DELETED == "N" && x.Appointment.IS_ARCHIVED == "N" && x.IS_ARCHIVED == "N"
&& ((x.Appointment.APPOINTMENT_DATETIME.HasValue && x.Appointment.APPOINTMENT_DATETIME.Value.Date == DateTime.Today.Date)
|| (!x.Appointment.APPOINTMENT_DATETIME.HasValue && x.ACTIVITY_STATUS_ID == _appSettings.CASE_ACTIVITY_STATUS_ID_PENDING)))
.Include(x => x.Activity_Lookup).Include(x => x.Appointment).ThenInclude(x => x.Cms_Client).Include(x => x.Cms_Case)
.ToListAsync();
假设您对 GetRepository()
方法有足够的控制权,可以使 it return 成为您的模拟存储库,模拟方法本身相当简单(如果有点冗长)。我只是将 GetAll
方法转储到一个名为 IRepository
的接口中,这就是模拟的样子。在 Returns
方法内部,您可以访问每个参数以根据需要执行或忽略。
var mock = new Moq.Mock<IRepository>();
mock.Setup(a => a.GetAll<int>(It.IsAny<Expression<Func<int, bool>>>(), It.IsAny<Func<IQueryable<int>, IOrderedQueryable<int>>>(), It.IsAny<Func<IQueryable<int>, IIncludableQueryable<int, object>>>(), It.IsAny<bool>()))
.Returns<Expression<Func<int, bool>>, Func<IQueryable<int>, IOrderedQueryable<int>>, Func<IQueryable<int>, IIncludableQueryable<int, object>>, bool>((param1, param2, param3, param4) =>
{
return new[] { 1, 2, 3 }.AsQueryable();
});
var result = mock.Object.GetAll<int>();
从这里开始,如果不查看更多代码,我们将无能为力。不过,从抽象的角度来说,您将获取 mock.Object
(属于 IRepository
类型)并将其提供给 GetRepository() 从中提取的任何集合。当然,还要注意,我使用了 int 作为通用参数——您可以将其替换为您正在使用的任何类型。可以制作一个接受通用参数的模拟,但希望这不是必需的!