c# - 正在测试的方法调用 IQueryable.SingleOrDefault 时出错

标签 c# entity-framework unit-testing iqueryable fakeiteasy

我正在使用 Entity Framework 和 FakeItEasy 进行单元测试。

有许多单元测试方法,它们都可以 - DbSet 正在被模拟,一切都很好。特别是,由于混凝土对 IQueryable.SingleOrDefault 的方法调用而失败,出现以下错误:

Result Message: 
Test method BLL.Tests.TrackerBLLTests.GetTracker_NoCache_No_User_Success threw exception: 
System.ArgumentException: Expression of type '' cannot be used for parameter of type 'System.Linq.IQueryable`1[Model.Tracker]' of method 'Model.Tracker SingleOrDefault[Tracker](System.Linq.IQueryable`1[Mobiltracker.Model.Tracker])'
Result StackTrace:  
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
   at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
   at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
   at System.Linq.Queryable.SingleOrDefault[TSource](IQueryable`1 source)
   at BLL.TrackerBLL.GetTracker(Int32 trackerId, Nullable`1 _userId) in ...\TrackerBLL.cs:line 655
   at BLL.Tests.TrackerBLLTests.GetTracker_NoCache_No_User_Success() in ...\TrackerBLLTests.cs:line 145

测试方法(改编):

[TestMethod]
public void GetTracker_NoCache_No_User_Success()
{
    var trackers = new List<Tracker> { new Tracker { TrackerId = 1 } };
    A.CallTo(() => m_iUnitOfWork.GetModelContainer().Trackers).Returns(PrepareAndGenerateFakeDbSet<Tracker>(trackers));
    var trackerBLL = A.Fake<TrackerBLL>(...);
    var returnedTracker = trackerBLL.GetTracker(1);

    Assert.IsNotNull(returnedTracker);
    Assert.AreSame(returnedTracker, m_trackerList[0]);
}

PrepareAndGenerateFakeDbSet 方法(完整):

public static DbSet<T> PrepareAndGenerateFakeDbSet<T>(List<T> _dataForDbSet) where T : class
{
    var queryableList = _dataForDbSet.AsQueryable<T>();
    var fakeDbSet = A.Fake<DbSet<T>>(builder => builder.Implements(typeof(IQueryable<T>)));

    A.CallTo(() => ((IQueryable<T>)fakeDbSet).Expression).Returns(queryableList.Expression);
    A.CallTo(() => ((IQueryable<T>)fakeDbSet).ElementType).Returns(queryableList.ElementType);
    A.CallTo(() => ((IQueryable<T>)fakeDbSet).GetEnumerator()).Returns(queryableList.GetEnumerator());

    return fakeDbSet;
}

正在测试(改编)的方法:

(...)
Tracker returnData = null;
var query = from t in Model.Trackers
            where t.TrackerId == trackerId
            select t;
returnData = query.SingleOrDefault(); //The error happens here and happens with Single(), First() or FirstOrDefault() extensions methods...
(...)
return returnData;

有什么想法吗?提前致谢!

最佳答案

刚刚发现,在我的试验和失败例程中,使用下面的类来模拟我的 DbSet 可以按预期工作:
http://pastebin.com/wQwbxhHr

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;

public class MockDbSet<TEntity> : DbSet<TEntity>, IQueryable<TEntity> where TEntity : class
{
    private List<TEntity> list = null;

    /// <summary>Initializes a new instance of the MockDbSet class.</summary>
    public MockDbSet(IEnumerable<TEntity> collection)
    {
        this.list = new List<TEntity>(collection);
    }

    public override IEnumerable<TEntity> AddRange(IEnumerable<TEntity> entities)
    {
        list.AddRange(entities);

        return list;
    }

    public override TEntity Add(TEntity entity)
    {
        list.Add(entity);

        return entity;
    }

    public override TEntity Attach(TEntity entity)
    {
        return entity;
    }

    public new TDerivedEntity Create<TDerivedEntity>() where TDerivedEntity : class, TEntity
    {
        return (TDerivedEntity)list.FirstOrDefault();
    }

    public override TEntity Create()
    {
        return list.FirstOrDefault();
    }

    public override TEntity Find(params object[] keyValues)
    {
        return null;
    }

    public override System.Collections.ObjectModel.ObservableCollection<TEntity> Local
    {
        get { return new System.Collections.ObjectModel.ObservableCollection<TEntity>(this.list); }
    }

    public override TEntity Remove(TEntity entity)
    {
        list.Remove(entity);
        return entity;
    }

    public IEnumerator<TEntity> GetEnumerator()
    {
        return list.GetEnumerator();
    }

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return list.GetEnumerator();
    }

    public Type ElementType
    {
        get { return this.list.AsQueryable().ElementType; }
    }

    public System.Linq.Expressions.Expression Expression
    {
        get { return this.list.AsQueryable().Expression; }
    }

    public IQueryProvider Provider
    {
        get { return this.list.AsQueryable().Provider; }
    }
}

关于c# - 正在测试的方法调用 IQueryable.SingleOrDefault 时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23135546/

相关文章:

javascript - 使用 Tape 测试客户端 JS(窗口未定义)

c# - 可以在 AssemblyCleanup 方法中访问 TestContext 吗?

c# - Unity异常: Transform child out of bounds

c# - Entity Framework 6 中存储过程的执行是否需要调用 SaveChanges?

javascript - 如何为带有服务的 Controller 编写单元测试

c# - 应该在 DTO 模型中还是在目标实体模型中执行计算?

asp.net - 如何使用 Entity Framework 代码优先实现在迁移时更新每一行的唯一值

c# - 我应该将哈希值保存到哪里以便将其存储到应用程序中?

c# - 使用语句的格式/缩进 (C#)

c# - Graphics.DrawImage 在 x86 和 x64 上创建不同的图像数据