在我的示例代码中测试 FirstOrDefaultAsync() 时出现问题
我有下面的方法,我通过用户名获取用户 ID,并且我已经为其编写了测试。但是,使用 FirstOrDefaultAsync() 时测试不起作用。如果我切换到 FirstOrDefault(),测试工作正常。这是代码:
正在测试的方法:
public async Task<int> GetUserId(string userName)
{
return await _unitofWork.Repository<UserEntity>().Entities
.Where(u => u.UserName == userName)
.Select(i => i.Id)
.FirstOrDefaultAsync();
}
测试代码:
[Fact]
public async Task GetUserIdTests()
{
//Arrange
var userEntity= new List<UserEntity>
{
new UserEntity
{
UserName = "testuser", Id = 1
}
};
var repositoryMock = new Mock<IGenericRepository<UserEntity>>();
repositoryMock.Setup(r => r.Entities).Returns(new TestAsyncEnumerable<UserEntity>(systemUsers).AsQueryable());
_unitOfWorkMock.Setup(u => u.Repository<UserEntity>()).Returns(repositoryMock.Object);
var service= new service(_userContextMock.Object,_vaultServiceMock.Object);
//Act
var result = await service.GetUserId("testuser");
//Assert
Assert.NotEqual(0, result);
}
问题: 这只是我为测试 FirstOrDefaultAsync() 方法而创建的示例,但它不起作用。使用 FirstOrDefault() 时测试工作正常,但使用 FirstOrDefaultAsync() 时测试失败。
支持代码: 这是我用来支持测试中的异步操作的 TestAsyncEnumerable 类:
public class TestAsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
{
public TestAsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
public TestAsyncEnumerable(Expression expression) : base(expression) { }
public IAsyncEnumerator<T> GetAsyncEnumerator(CancellationToken cancellationToken = default)
{
return new TestAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IAsyncEnumerator<T> IAsyncEnumerable<T>.GetAsyncEnumerator(CancellationToken cancellationToken)
{
return GetAsyncEnumerator(cancellationToken);
}
IQueryProvider IQueryable.Provider => new TestAsyncQueryProvider<T>(this);
}
public class TestAsyncEnumerator<T> : IAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public TestAsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public ValueTask DisposeAsync()
{
_inner.Dispose();
return ValueTask.CompletedTask;
}
public ValueTask<bool> MoveNextAsync()
{
return new ValueTask<bool>(_inner.MoveNext());
}
public T Current => _inner.Current;
}
public class TestAsyncQueryProvider<T> : IAsyncQueryProvider
{
private readonly IQueryProvider _inner;
public TestAsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
return new TestAsyncEnumerable<T>(expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new TestAsyncEnumerable<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)
{
return Execute<TResult>(expression);
}
public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
{
return new TestAsyncEnumerable<TResult>(expression);
}
}
问题: 使用 FirstOrDefaultAsync() 时可能导致测试失败的原因是什么?我实现 TestAsyncEnumerable 类的方式或异步测试的设置方式是否有问题?
错误: 信息: System.ArgumentException:参数表达式无效
堆栈跟踪: IQueryProvider.Execute[TElement](表达式表达式) TestAsyncQueryProvider
1.Execute[TResult](Expression expression) line 72 TestAsyncQueryProvider
1.ExecuteAsync[TResult](表达式表达式,CancellationToken取消令牌) line 78
EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo 运算符MethodInfo, IQueryable1 source, Expression expression, CancellationToken cancellationToken) EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable
1 源, CancellationToken CancellationToken)
EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 源,CancellationToken 取消令牌)
这要么是
TestAsyncEnumerable
中的问题,要么是在幕后使用它执行操作的 EF 代码中的问题。它不特定于 ASP.NET Core 或模拟。
我将您的
TestAsyncEnumerable
代码复制/粘贴到新的控制台应用程序中,然后编写了以下最小示例:
using Microsoft.EntityFrameworkCore;
var list = new List<string> { "ab", "cde", "fgh", "ij" };
var query = new TestAsyncEnumerable<string>(list);
var first = await query.FirstOrDefaultAsync();
Console.WriteLine(first);
...并且由于同样的异常而失败。 (最初我包含了
Select
和 Where
子句,但不需要它们来重现该问题。)
目前还不清楚
TestAsyncEnumerable
来自哪里(无论是本土的还是来自博客文章或类似内容),但看起来这就是您需要解决的问题。