如何在对象上设置linq扩展名?我的情况DbSet
。这是我的代码:
this.workflowStateSet
.Setup(m => m.Where(It.IsAny<Expression<Func<Model.WorkflowState, int, bool>>>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
然而,它给了我例外不是很熟悉的例外:
System.NotSupportedException:Expression引用一个方法 不属于模拟对象:
m => m.Where<WorkflowState>
我会感激任何提示。
答案 0 :(得分:2)
使用存储库模式为数据检索添加一个抽象层。然后可以嘲笑这种抽象。
例如,如果您尝试检索stateId等于1的所有工作流程,那么而不是调用类似这样的内容
var result = DbSet.WorkflowState.Where(w => w.stateId == 1);
将此代码移动到另一个类中,然后创建方法签名的接口。
public interface IWorkflowStateSetRepository{
IQueryable<Model.WorkflowState> GetAllWorkflows(int state);
}
实施
public class WorkflowStateSetRepository : IWorkflowStateSetRepository{
public IQueryable<Model.WorkflowState> GetAllWorkflows(int state){
return DbSet.WorkflowState .Where(w => w.stateId == state);
}
}
在调用代码中获取IWorkflowStateSetRepository的实例(可能来自您的IoC容器)并调用GetAllWorkflows()方法。这将为您提供与以前相同的结果,但您现在可以在测试中模拟界面并设置对该方法的调用。
this.MockedIWorkflowStateSetRepository.Setup(m => m.GetAllWorkflows(It.IsAny<int>()))
.Returns(new List<Model.WorkflowState>().AsQueryable());
这段代码更易于维护,并且(通过适当命名的变量和方法)也可以更好地传达意图。
此处更详细地讨论了存储库模式;
答案 1 :(得分:2)
此扩展方法将有助于模拟DbSet
public static class MockDbSetExtensions {
public static Mock<DbSet<T>> AsDbSetMock<T>(this IEnumerable<T> list) where T : class {
IQueryable<T> queryableList = list.AsQueryable();
Mock<DbSet<T>> dbSetMock = new Mock<DbSet<T>>();
dbSetMock.As<IQueryable<T>>().Setup(x => x.Provider).Returns(queryableList.Provider);
dbSetMock.As<IQueryable<T>>().Setup(x => x.Expression).Returns(queryableList.Expression);
dbSetMock.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(queryableList.ElementType);
dbSetMock.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(() => queryableList.GetEnumerator());
return dbSetMock;
}
}
你可以像这样使用它。
//Arrange
var data = new List<Model.WorkflowState>();
//you would populate your list as needed.
//convert it to a mock DbSet that uses the list as its datasource
var workflowStateSet = data.AsDbSetMock();
var dbSet = workflowStateSet.Object;
//Act
var items = dbSet.Where("Your expression here");
//Assert
//....
答案 2 :(得分:1)
您是否正在尝试模拟真实的DbSet实例?因为这将无法正常工作,因为错误消息试图解释你。要模拟类型,它必须是接口或具有虚拟成员(抽象成员也是虚拟成员)。
您可以尝试模拟IDbSet或创建自定义DbSet类,例如类似下面的类
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
public class DbSetMock<T> : DbSet<T>, IDbSet<T>
where T : class
{
private readonly ICollection<T> _contentCollection;
public DbSetMock(IList<T> contentCollection = null)
{
_contentCollection = new Collection<T>(contentCollection ?? new List<T>());
AddedEntities = new List<T>();
RemovedEntities = new List<T>();
AttachedEntities = new List<T>();
}
public void OverrideContentCollection(IEnumerable<T> newData)
{
_contentCollection.Clear();
_contentCollection.AddRange(newData);
}
public IList<T> AddedEntities { get; private set; }
public IList<T> AttachedEntities { get; private set; }
public override ObservableCollection<T> Local
{
get
{
throw new NotImplementedException();
}
}
public IList<T> RemovedEntities { get; private set; }
public Type ElementType
{
get
{
return typeof(T);
}
}
public Expression Expression
{
get
{
return _contentCollection.AsQueryable().Expression;
}
}
public IQueryProvider Provider
{
get
{
return _contentCollection.AsQueryable().Provider;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _contentCollection.GetEnumerator();
}
public override T Add(T entity)
{
AddedEntities.Add(entity);
_contentCollection.Add(entity);
return entity;
}
public override T Attach(T entity)
{
AttachedEntities.Add(entity);
var matchingEntity = _contentCollection.SingleOrDefault(x => x.Id == entity.Id);
if (matchingEntity != null)
{
_contentCollection.Remove(matchingEntity);
}
_contentCollection.Add(entity);
return entity;
}
public override TDerivedEntity Create<TDerivedEntity>()
{
throw new NotImplementedException();
}
public override T Create()
{
throw new NotImplementedException();
}
public override T Find(params object[] keyValues)
{
throw new NotImplementedException();
}
public override T Remove(T entity)
{
RemovedEntities.Add(entity);
_contentCollection.Remove(entity);
return entity;
}
}
您可以使用构造函数参数来设置将由db set检索的内容。
希望这有帮助。