LINQ模拟IDbSet GetEnumerator时失败
本文关键字:失败 GetEnumerator IDbSet 模拟 LINQ | 更新日期: 2023-09-27 17:54:14
我试图模拟System.Data.Entity.IDbSet,使其返回一些数据(在这种情况下只是一个空集合):
var mock = new Mock<IDbSet<Setting>>();
mock.Setup(x => x.GetEnumerator()).Returns(Enumerable.Empty<Setting>().GetEnumerator());
var myEnumerator = mock.Object.GetEnumerator();
var count = mock.Object.Count();
这里myEnumerator将有一个非空值,正如预期的那样,但是mock.Object.Count()将抛出ArgumentNullException
System.ArgumentNullException : Value cannot be null.
Parameter name: arguments
at System.Linq.Expressions.Expression.RequiresCanRead(Expression expression, String paramName)
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ref ReadOnlyCollection`1 arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at System.Linq.Queryable.Count(IQueryable`1 source)
如果我用IEnumerable替换IDbSet,它会按预期工作(count为零)。为什么IDbSet没有像我期望的那样被嘲笑?
编辑看起来LINQ尝试使用IQueryable接口,因为这是有效的:
var mock = new Mock<IDbSet<Setting>>();
var myQueryable = Enumerable.Empty<Setting>().AsQueryable();
mock.Setup(m => m.Provider).Returns(myQueryable.Provider);
mock.Setup(m => m.Expression).Returns(myQueryable.Expression);
mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator());
var count = mock.Object.Count();
原来LINQ对IQueryable有显式实现:
public static int Count<TSource>(this IQueryable<TSource> source) {
if (source == null)
throw Error.ArgumentNull("source");
return source.Provider.Execute<int>(
Expression.Call(
null,
((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TSource)),
new Expression[] { source.Expression }
));
}
实际上这很有意义,否则LINQ表达式如何将表达式转换为实体框架查询。
所以我必须模拟提供者和表达式:
var mock = new Mock<IDbSet<Setting>>();
var myQueryable = Enumerable.Empty<Setting>().AsQueryable();
mock.Setup(m => m.Provider).Returns(myQueryable.Provider);
mock.Setup(m => m.Expression).Returns(myQueryable.Expression);
mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator());
var count = mock.Object.Count();
你应该改变
mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator())
mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator)