使用 MockQueryable 时,源 'IQueryable' 的提供程序未实现 'IAsyncQueryProvider'
The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider' when using MockQueryable
我正在使用 .NET 6,我正在尝试模拟 IQueryable return 以使用 MockQueryable 库实现 IAsyncQueryProvider,但是我在使用和不使用该库时都面临着同样的错误:
Message:
System.InvalidOperationException : The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations.
Stack Trace:
EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable1 source, Expression expression, CancellationToken cancellationToken) EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable
1 source, CancellationToken cancellationToken)
EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
UserService.GetExistingUser(String externalId, CancellationToken cancellationToken) line 81
UserService.CreateAsync(UserDto dto, CancellationToken cancellationToken) line 21
UserServiceTests.CreateAsync_ShouldCreateUser_WhenUserDoesNotExist() line 46
--- End of stack trace from previous location ---
也许有人可以帮我找出可能是明显错误的地方?
这是我的单元测试class:
public class UserServiceTests
{
private readonly UserService _sut;
private readonly Mock<IRepository<User>> _userRepositoryMock = new();
public UserServiceTests()
{
_sut = new UserService(_userRepositoryMock.Object);
}
[Fact]
public async Task CreateAsync_ShouldCreateUser_WhenUserDoesNotExist()
{
// Arrange
var dto = new UserDto
{
EmailAddress = "createAsyncTest@email.com",
ExternalId = "externalId2",
Name = "Create Async"
};
var users = new List<User>();
var mock = users.BuildMock();
_userRepositoryMock.Setup(x => x.Find(y => y.ExternalId == dto.ExternalId)).Returns(mock).Verifiable();
var user = UserMapper.GetUserExpression(null).Compile().Invoke(dto);
_userRepositoryMock.Setup(x => x.InsertAsync(user, true, default)).Verifiable();
// Act
var res = await _sut.CreateAsync(dto);
// Assert
Assert.NotNull(res);
_userRepositoryMock.Verify();
}
}
这就是我实现通用存储库的方式:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal TestContext _context;
internal DbSet<TEntity> _dbSet;
public Repository(TestContext context)
{
_context = context;
_context.Database.SetCommandTimeout(300);
_dbSet = context.Set<TEntity>();
}
public IQueryable<TEntity> All() => _dbSet;
public IQueryable<TEntity> Find() => All();
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Where(predicate);
}
}
这是我的用户服务:
public class UserService : IUserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
public async Task<UserDto> CreateAsync(UserDto dto, CancellationToken cancellationToken = default)
{
var existingUser = await GetExistingUser(dto.ExternalId, cancellationToken);
if (existingUser != null)
throw new Exception("User already exists!");
var user = UserMapper.GetUserExpression(null).Compile().Invoke(dto);
await _userRepository.InsertAsync(user, true, cancellationToken);
return UserMapper.GetUserDtoExpression().Compile().Invoke(user);
}
private async Task<User> GetExistingUser(string externalId, CancellationToken cancellationToken = default)
{
return await _userRepository
.Find(x => x.ExternalId == externalId)
.FirstOrDefaultAsync(cancellationToken);
}
}
传递给 _userRepository.Find() 的 Expression<Func<User, bool>>
类型的谓词与您在 _userRepositoryMock.Setup() 中指定的表达式不同(它们具有相同的逻辑和相同的 externalId,但它们是不同的实例).
而不是
_userRepositoryMock.Setup(x => x.Find(y => y.ExternalId == dto.ExternalId)).Returns(mock)
试试这个:
_userRepositoryMock.Setup(x => x.Find(It.IsAny<Expression<Func<User, bool>>>()).Returns(predicate => mock.Where(predicate))
这样,传递给 .Find() 方法的任何表达式都将按原样应用于模拟存储库。
我正在使用 .NET 6,我正在尝试模拟 IQueryable return 以使用 MockQueryable 库实现 IAsyncQueryProvider,但是我在使用和不使用该库时都面临着同样的错误:
Message: System.InvalidOperationException : The provider for the source 'IQueryable' doesn't implement 'IAsyncQueryProvider'. Only providers that implement 'IAsyncQueryProvider' can be used for Entity Framework asynchronous operations.
Stack Trace: EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable
1 source, Expression expression, CancellationToken cancellationToken) EntityFrameworkQueryableExtensions.ExecuteAsync[TSource,TResult](MethodInfo operatorMethodInfo, IQueryable
1 source, CancellationToken cancellationToken) EntityFrameworkQueryableExtensions.FirstOrDefaultAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken) UserService.GetExistingUser(String externalId, CancellationToken cancellationToken) line 81 UserService.CreateAsync(UserDto dto, CancellationToken cancellationToken) line 21 UserServiceTests.CreateAsync_ShouldCreateUser_WhenUserDoesNotExist() line 46 --- End of stack trace from previous location ---
也许有人可以帮我找出可能是明显错误的地方?
这是我的单元测试class:
public class UserServiceTests
{
private readonly UserService _sut;
private readonly Mock<IRepository<User>> _userRepositoryMock = new();
public UserServiceTests()
{
_sut = new UserService(_userRepositoryMock.Object);
}
[Fact]
public async Task CreateAsync_ShouldCreateUser_WhenUserDoesNotExist()
{
// Arrange
var dto = new UserDto
{
EmailAddress = "createAsyncTest@email.com",
ExternalId = "externalId2",
Name = "Create Async"
};
var users = new List<User>();
var mock = users.BuildMock();
_userRepositoryMock.Setup(x => x.Find(y => y.ExternalId == dto.ExternalId)).Returns(mock).Verifiable();
var user = UserMapper.GetUserExpression(null).Compile().Invoke(dto);
_userRepositoryMock.Setup(x => x.InsertAsync(user, true, default)).Verifiable();
// Act
var res = await _sut.CreateAsync(dto);
// Assert
Assert.NotNull(res);
_userRepositoryMock.Verify();
}
}
这就是我实现通用存储库的方式:
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
internal TestContext _context;
internal DbSet<TEntity> _dbSet;
public Repository(TestContext context)
{
_context = context;
_context.Database.SetCommandTimeout(300);
_dbSet = context.Set<TEntity>();
}
public IQueryable<TEntity> All() => _dbSet;
public IQueryable<TEntity> Find() => All();
public IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> predicate)
{
return _dbSet.Where(predicate);
}
}
这是我的用户服务:
public class UserService : IUserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
public async Task<UserDto> CreateAsync(UserDto dto, CancellationToken cancellationToken = default)
{
var existingUser = await GetExistingUser(dto.ExternalId, cancellationToken);
if (existingUser != null)
throw new Exception("User already exists!");
var user = UserMapper.GetUserExpression(null).Compile().Invoke(dto);
await _userRepository.InsertAsync(user, true, cancellationToken);
return UserMapper.GetUserDtoExpression().Compile().Invoke(user);
}
private async Task<User> GetExistingUser(string externalId, CancellationToken cancellationToken = default)
{
return await _userRepository
.Find(x => x.ExternalId == externalId)
.FirstOrDefaultAsync(cancellationToken);
}
}
传递给 _userRepository.Find() 的 Expression<Func<User, bool>>
类型的谓词与您在 _userRepositoryMock.Setup() 中指定的表达式不同(它们具有相同的逻辑和相同的 externalId,但它们是不同的实例).
而不是
_userRepositoryMock.Setup(x => x.Find(y => y.ExternalId == dto.ExternalId)).Returns(mock)
试试这个:
_userRepositoryMock.Setup(x => x.Find(It.IsAny<Expression<Func<User, bool>>>()).Returns(predicate => mock.Where(predicate))
这样,传递给 .Find() 方法的任何表达式都将按原样应用于模拟存储库。