我使用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;
有什么想法吗?提前谢谢!
答案 0 :(得分:2)
刚刚在我的试验和失败例程中发现,使用下面的类来模拟我的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; }
}
}