要对应用程序进行单元测试,我们使用Moq创建了DbSet的模拟,如下所示:
public static class RepositoryHelper
{
public static Mock<DbSet<T>> GetQueryableMockDbSet<T>(ICollection<T> sourceList, bool queryDeletedEntities = false) where T : EntityBase
{
IQueryable<T> queryable = queryDeletedEntities
? sourceList.AsQueryable()
: sourceList.AsQueryable().Where(e => !e.IsDeleted);
var dbSet = new Mock<DbSet<T>>();
dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(() => queryable.GetEnumerator());
dbSet.Setup(d => d.Add(It.IsAny<T>())).Returns<T>(e =>
{
sourceList.Add(e);
return e;
});
dbSet.Setup(d => d.Remove(It.IsAny<T>())).Returns<T>(e =>
{
sourceList.Remove(e);
return e;
});
return dbSet;
}
}
我们存储库的相关部分是这样的:
public class Repository<T> : IRepository<T>
where T : EntityBase
{
public Repository(DbSet<T> set)
{
Set = set;
}
/// <summary>
/// Returns the orginal entity framework set.
/// Use this property to access change tracked or all existing entities.
/// </summary>
protected DbSet<T> Set { get; }
/// <summary>
/// Returns the query.
/// Use this property as a foundation for all get queries.
/// </summary>
protected virtual IQueryable<T> Query => Set;
public IQueryable<T> Get()
{
return Query;
}
protected static IQueryable<TDerived> ApplyIncludes<TDerived>(IQueryable<TDerived> query, Expression<Func<TDerived, object>>[] propertiesToInclude) where TDerived : T
{
if (propertiesToInclude.Length != 0)
{
foreach (var propertyToInclude in propertiesToInclude)
{
query = query.Include(propertyToInclude);
}
}
return query;
}
}
我的问题是,在影响query
时,模拟DbSet Repository.ApplyIncludes
在query = query.Include(propertyToInclude);
中为空(正在使用System.Data.Entity.QueryableExtensions
中的include);真正的实施效果很好。另外,如果我将Repository.Query
修改为返回protected virtual IQueryable<T> Query => Set.Where(e => true);
,则会解决此问题。
query
中Repository.ApplyIncludes
的类型在仅使用Castle.Proxies.DbSet'1Proxy
时为Set
,在使用System.Linq.EnumerableQuery<EntityType>
时为Set.Where(e => true)
。
我不确定我们是否错过了RepositoryHelper.GetQueryableMockDbSet
中的某些内容,是否偶然发现了Moq或其他错误。我还没有找到解决RepositoryHelper.GetQueryableMockDbSet
中问题的方法,也不想在生产性代码中包含protected virtual IQueryable<T> Query => Set.Where(e => true);
(因为它只能解决测试问题)。如果有人能指出我正确的方向,我将不胜感激。