问题描述
在C#和EFCore中,我使用以下内容模拟DbSet可查询对象:
public static DbSet<T> GetQueryableMockDbSet<T>(List<T> sourceList) where T : class
{
var queryable = sourceList.AsQueryable();
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>())).Callback<T>((s) => sourceList.Add(s));
return dbSet.Object;
}
在许多情况下都可以使用,但是我不支持EF .Find()方法。
我想这样添加它:
dbSet.Setup(d => d.Find(It.IsAny<int>())).Callback<int>((s) => sourceList.Where(x => x.ID == s));
...但是由于T是泛型,所以我不能依靠ID属性进行检查。
我考虑过两种解决方法:
#1:将签名的T:类更改为T:IFindable的某种形式我将.ID始终用作属性,这样就可以了,但随后我需要将一堆IFinable添加到不可测试的类,这很丑陋,或者
#2:输入一个回调,该回调使用反射来读取字段名称/值,查找ID字段并匹配值
#2可能是我会做的。这很丑陋,但至少它包含在此测试帮助器中,不需要回退到非测试代码。
有人有更聪明的方式来处理它吗?
解决方法
正如其他人在评论中提到的那样,建议使用内存提供程序。
https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/
我们将测试倍数用于EF Core的内部测试。但是,我们永远不会尝试模拟DbContext或IQueryable。这样做是困难,麻烦且脆弱的。不要这样做。
如果要继续嘲笑,可以尝试以下方法:
IFindable
这样,您只需在要测试的类上实现IFindable
。
另外,我会打电话给IEntity
{{1}}