我正在从Entify Framework嘲笑DbSet。我想使用它的扩展方法ToListAsync
。这就是我这样做的方式,低于我的尝试结果(常规ToList
有效):
IQueryable<DbUser> userData = MockedData.Instance.Users; // this is just a property to get custom IQueryable set of data for testing
var dbSetMock = new Mock<DbSet<DbUser>>();
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.Provider).Returns(userData.Provider);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.Expression).Returns(userData.Expression);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.ElementType).Returns(userData.ElementType);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.GetEnumerator()).Returns(userData.GetEnumerator());
/*
I've put it here so you can see how I tried to approach my problem
dbSetMock.Setup(x => x.ToListAsync())
.Returns(Task.FromResult(userData.ToList()));
*/
var testAsync = dbSetMock.Object.ToListAsync();
var testRegular = dbSetMock.Object.ToList();
结果:
变量testRegular
具有预期的值。但变量testAsync
的值如下:
当我取消注释我尝试设置ToListAsync
以返回任何内容的部分时,我会得到如下异常:
{"Expression references a method that does not belong to the mocked object: x => x.ToListAsync<DbUser>()"}
我很感激任何建议。我应该切换到Fakes吗?是否支持此类功能?
答案 0 :(得分:2)
我成功找到并使用了this代码:
dbSetMock.As<IDbAsyncEnumerable<DbUser>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new AsyncEnumerator<DbUser>(userData.GetEnumerator()));
使用以下支持类(注意使用C#6速记功能):
class AsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose() => _inner.Dispose();
public Task<bool> MoveNextAsync(CancellationToken cancellationToken) => Task.FromResult(_inner.MoveNext());
public T Current => _inner.Current;
object IDbAsyncEnumerator.Current => Current;
}
错误的根本原因是Moq无法模拟静态方法,至少目前是这样。