模拟IDbSet GetEnumerator时LINQ失败

时间:2014-03-28 06:58:20

标签: c# linq entity-framework moq

我正在尝试模拟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将具有非null值,如预期的那样,但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,它按预期工作(计数为零)。为什么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();

2 个答案:

答案 0 :(得分:4)

事实证明,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();

答案 1 :(得分:0)

你应该改变

mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator())

mock.Setup(m => m.GetEnumerator()).Returns(myQueryable.GetEnumerator)