我正在尝试模拟DbContext和DbSet。这适用于我之前的单元测试,但是当我的代码第二次在DbSet上调用ToList方法时出现问题。
首先,dbSet.ToList()返回模拟结果。 第二个返回0个元素;
var queryableData = new List<string>{ "a", "b", "c" }.AsQueryable();
var mockDbSet = new Mock<DbSet<string>>();
var q = mockDbSet.As<IQueryable<string>>();
q.Setup(m => m.Provider).Returns(queryableData.Provider);
q.Setup(m => m.Expression).Returns(queryableData.Expression);
q.Setup(m => m.ElementType).Returns(queryableData.ElementType);
q.Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator());
DbSet<string> dbset = mockDbSet.Object;
IQueryable<string> query = dbset;
//RESULTS: abc
var a1 = dbset.ToList();
foreach (var a in a1)
Console.Write(a);
//NO RESULTS
var a2 = dbset.ToList();
foreach (var a in a2)
Console.Write(a);
答案 0 :(得分:39)
每次调用GetEnumerator
时,都会返回相同的枚举器实例。当它枚举一次时,它就完成了,EF没有调用它的Reset
方法,而是要求新的枚举器。
但是你会返回那个刚刚产生了所有元素而不再产生的元素。
相反,返回一个返回枚举器的函数,每次请求它时都会返回一个新的枚举器。
q.Setup(m => m.GetEnumerator()).Returns( () => queryableData.GetEnumerator() );
答案 1 :(得分:2)
我只想添加到Wiktor Zychla的回答我的小部分。如果有人正在寻找此模拟的异步版本(来自本教程:http://msdn.microsoft.com/en-us/data/dn314429.aspx#async),那么这是我对TestDbAsyncEnumerator<T>
类的修改:
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestDbAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public TestDbAsyncEnumerator(Func<IEnumerator<T>> valueFunction)
{
_inner = valueFunction();
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current
{
get { return _inner.Current; }
}
object IDbAsyncEnumerator.Current
{
get { return Current; }
}
}
然后像Wiktor建议你必须使用委托设置它,所以在异步的情况下它会是这样的:
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<Blog>(() => data.GetEnumerator()));
如果有人想要获取相关内容,请点击此处:https://github.com/kelostrada/EntityFrameworkWithMock.Test
答案 2 :(得分:2)
我无法评论Wiktor的帖子,因为我没有足够的声誉,但我想在Wiktor的答案中添加一些额外内容。
代码
mockSet.Setup((m => m.GetEnumerator()).Returns(() => data.GetEnumerator())
如果你在示例中给它一个零参数lambda(至少我正在使用的版本),它将失败。 传递一个从未使用的参数将允许它满足签名要求。
mockSet.Setup((m => m.GetEnumerator()).Returns(x => data.GetEnumerator())
然而,将编译,并按预期工作。
这也适用于Kelu的答案(尽管他已将lambda添加到了错误的位置。
mockSet.As<IDbAsyncEnumerable<Blog>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(x => new TestDbAsyncEnumerator<Blog>(data.GetEnumerator()));
我不想在这里挑剔答案,我只是加入,因为我自己犯了这些错误:)
答案 3 :(得分:0)
如果你把&#34; Where&#34;在.ToList()调用之前,数据应保持存在。
var a1 = dbset.Where(m => m != null).ToList();
var a2 = dbset.Where(m => m != null).ToList();