C# 模拟DbSet<;T>;内联

C# 模拟DbSet<;T>;内联,c#,unit-testing,entity-framework-6,moq,dbset,C#,Unit Testing,Entity Framework 6,Moq,Dbset,我正在使用.NET4.5、EF6和Moq进行单元测试。我试图模拟一些Db数据进行测试。我举了一个例子来说明如何使用 但它会导致System.InvalidCastException:无法将类型为'System.Collections.Generic.List1[Saga.Services.Legal.Website.Journey]的对象强制转换为类型为'System.Data.Entity.DbSet1[Saga.Services.Legal.Website.Journey]. 如何模拟DbS

我正在使用
.NET4.5
EF6
Moq
进行单元测试。我试图模拟一些Db数据进行测试。我举了一个例子来说明如何使用

但它会导致
System.InvalidCastException:无法将类型为'System.Collections.Generic.List1[Saga.Services.Legal.Website.Journey]的对象强制转换为类型为'System.Data.Entity.DbSet1[Saga.Services.Legal.Website.Journey].

如何模拟
DbSet
inline?


编辑:关于重复,标记我问题的人除了标题外,没有花力气阅读,今年将从圣诞老人那里得到沙林毒气。

使用您定义的方法,从列表中创建一个DbSet,在这种情况下,T是类型
旅程
,并假设
o.Travely
是类型
DbSet

private-DbSet-ToDbSet(List-sourceList),其中T:class
{
var queryable=sourceList.AsQueryable();
var dbSet=new Mock();
dbSet.As().Setup(m=>m.Provider).Returns(queryable.Provider);
设置(m=>m.Expression).Returns(queryable.Expression);
设置(m=>m.ElementType).Returns(queryable.ElementType);
dbSet.As().Setup(m=>m.GetEnumerator()).Returns(queryable.GetEnumerator());
Setup(d=>d.Add(It.IsAny()).Callback(sourceList.Add);
返回dbSet.Object;
}
私有void SomeOtherMethod()
{
var旅程=新旅程
{ 
SessionId=SessionId,
物业转易解答=新托收()
};
var-journeys=新列表{journey};
mockedbContext.Setup(o=>o.Journey)
.返回(()=>ToDbSet(行程));
}

如果你想把它放在一行,那么它是可能的,但在可读性方面不一定是可取的。

我昨天已经研究了几个小时了。@silleknarf的anwser是正确的,但不完整。异步方法将给出一个异常。我昨天在网上搜索了一下,找到了这个扩展方法作为解决方案。它适用于dotnet3.1。由于对接口进行了一些更改,以前的版本可能需要不同的实现。希望它对你们中的一些人有用。:)

公共静态类DbSet
{
公共静态DbSet ToDbSet(此列表sourceList),其中T:class
{
var queryable=sourceList.AsQueryable();
var dbSet=new Mock();
dbSet.As()
.Setup(m=>m.GetAsyncEnumerator(It.IsAny()))
.Returns(新的MockAsyncEnumerator(queryable.GetEnumerator());
dbSet.As()
.Setup(m=>m.Provider)
.Returns(新的MockAsyncQueryProvider(queryable.Provider));
设置(m=>m.Expression).Returns(queryable.Expression);
设置(m=>m.ElementType).Returns(queryable.ElementType);
dbSet.As().Setup(m=>m.GetEnumerator()).Returns(queryable.GetEnumerator());
Setup(d=>d.Add(It.IsAny()).Callback(sourceList.Add);
返回dbSet.Object;
}
私有类MockAsyncQueryProvider:IAsyncQueryProvider
{
私有只读IQueryProvider\u内部;
内部MockAsyncQueryProvider(IQueryProvider内部)
{
_内部=内部;
}
公共IQueryable CreateQuery(表达式)
{
返回新的MockAsyncEnumerable(表达式);
}
公共IQueryable CreateQuery(表达式)
{
返回新的MockAsyncEnumerable(表达式);
}
公共对象执行(表达式)
{
返回_inner.Execute(表达式);
}
公共TResult执行(表达式)
{
返回_inner.Execute(表达式);
}
public TResult ExecuteAsync(表达式表达式,CancellationToken CancellationToken=default)
{
var expectedResultType=typeof(TResult).GetGenericArguments()[0];
var executionResult=typeof(IQueryProvider)
.GetMethod(名称:nameof(IQueryProvider.Execute),genericParameterCount:1,类型:new[]{typeof(Expression)})
.MakeGenericMethod(expectedResultType)
.Invoke(这个新的[]{expression});
返回(TResult)类型(任务)
.GetMethod(name of(Task.FromResult))
?MakeGenericMethod(expectedResultType)
.Invoke(null,新[]{executionResult});
}
}
私有类MockAsyncEnumerable:EnumerableQuery、IAsyncEnumerable、IQueryable
{
IQueryProvider IQueryable.Provider=>新的MockAsyncQueryProvider(此);
public MockAsyncEnumerable(IEnumerable enumerable):基(enumerable){}
公共MockAsyncEnumerable(表达式):基(表达式){}
公共IAsyncEnumerator GetAsyncEnumerator(CancellationToken CancellationToken=默认值)
{
返回新的MockAsyncEnumerator(this.AsEnumerable().GetEnumerator());
}
}
私有类MockAsyncEnumerator:IAsyncEnumerator
{
私有只读IEnumerator\u内部;
公共T电流=>\u内部电流;
公共MockAsyncEnumerator(IEnumerator内部)
{
_内部=内部;
}
公共价值任务MoveNextAsync()
{
返回新的ValueTask(_inner.MoveNext());
}
公共价值任务处置同步()
{
_depose();
返回新的ValueTask();
}
}
}

试试这个@VadimMartynov Hi,谢谢链接,在文章中他们在哪里声明db set inline?另一种方法-不要模仿DBContext;)嗨,silleknarf谢谢你的回复。在您的回答中,我在哪里可以找到未使用扩展方法而声明为内联的DbSet?
TestExtensionMethods.AsDbSet(journes)
返回一个
DbSet
我现在已经删除了中扩展方法的使用
public static class TestExtensionMethods
{
       public static DbSet<T> AsDbSet<T>(this List<T> sourceList) where T : class
       {
           var queryable = sourceList.AsQueryable();

           var dbSet = new Mock<DbSet<T>>();
           dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
           dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
           dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
           dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
           dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(sourceList.Add);
           return dbSet.Object;
       }
}
var mockedDbContext = new Mock<OnlineLegal>();
mockedDbContext.Setup(o => o.Journey).Returns(() => (DbSet<Journey>)(new List<Journey> { new Journey { SessionId = sessionId, ConveyancingAnswer = new Collection<ConveyancingAnswer>()} }.AsEnumerable()));
private DbSet<T> ToDbSet<T>(List<T> sourceList) where T : class
{
    var queryable = sourceList.AsQueryable();

    var dbSet = new Mock<DbSet<T>>();
    dbSet.As<IQueryable<T>>().Setup(m => m.Provider).Returns(queryable.Provider);
    dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
    dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
    dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
    dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(sourceList.Add);
    return dbSet.Object;
}

private void SomeOtherMethod() 
{
    var journey = new Journey 
    { 
        SessionId = sessionId, 
        ConveyancingAnswer = new Collection<ConveyancingAnswer>()
    };
    var journeys = new List<Journey> { journey };  
    mockedDbContext.Setup(o => o.Journey)
                   .Returns(() => ToDbSet<Journey>(journeys));
}
public static class DbSet
{
    public static DbSet<T> ToDbSet<T>(this List<T> sourceList) where T : class
    {
        var queryable = sourceList.AsQueryable();
        var dbSet = new Mock<DbSet<T>>();

        dbSet.As<IAsyncEnumerable<T>>()
             .Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
             .Returns(new MockAsyncEnumerator<T>(queryable.GetEnumerator()));

        dbSet.As<IQueryable<T>>()
            .Setup(m => m.Provider)
            .Returns(new MockAsyncQueryProvider<T>(queryable.Provider));

        dbSet.As<IQueryable<T>>().Setup(m => m.Expression).Returns(queryable.Expression);
        dbSet.As<IQueryable<T>>().Setup(m => m.ElementType).Returns(queryable.ElementType);
        dbSet.As<IQueryable<T>>().Setup(m => m.GetEnumerator()).Returns(queryable.GetEnumerator());
        dbSet.Setup(d => d.Add(It.IsAny<T>())).Callback<T>(sourceList.Add);
        return dbSet.Object;
    }
    private class MockAsyncQueryProvider<TEntity> : IAsyncQueryProvider
    {
        private readonly IQueryProvider _inner;

        internal MockAsyncQueryProvider(IQueryProvider inner)
        {
            _inner = inner;
        }

        public IQueryable CreateQuery(Expression expression)
        {
            return new MockAsyncEnumerable<TEntity>(expression);
        }

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new MockAsyncEnumerable<TElement>(expression);
        }

        public object Execute(Expression expression)
        {
            return _inner.Execute(expression);
        }

        public TResult Execute<TResult>(Expression expression)
        {
            return _inner.Execute<TResult>(expression);
        }

        public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = default)
        {
            var expectedResultType = typeof(TResult).GetGenericArguments()[0];
            var executionResult = typeof(IQueryProvider)
                     .GetMethod(name: nameof(IQueryProvider.Execute), genericParameterCount: 1, types: new[] { typeof(Expression) })
                     .MakeGenericMethod(expectedResultType)
                     .Invoke(this, new[] {expression});

            return (TResult)typeof(Task)
                .GetMethod(nameof(Task.FromResult))
                ?.MakeGenericMethod(expectedResultType)
                .Invoke(null, new[] { executionResult });
        }
    }
    private class MockAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
    {
        IQueryProvider IQueryable.Provider => new MockAsyncQueryProvider<T>(this);

        public MockAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { } 
        public MockAsyncEnumerable(Expression expression) : base(expression) { } 

        public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
        {
            return new MockAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
        }
    }
    private class MockAsyncEnumerator<T> : IAsyncEnumerator<T>
    {
        private readonly IEnumerator<T> _inner;

        public T Current => _inner.Current;

        public MockAsyncEnumerator(IEnumerator<T> inner)
        {
            _inner = inner;
        }

        public ValueTask<bool> MoveNextAsync()
        {
            return new ValueTask<bool>(_inner.MoveNext());
        }
        public ValueTask DisposeAsync()
        {
            _inner.Dispose();

            return new ValueTask();
        }
    }
}