在模拟FromSql()方法时如何克服IQueryable不实现IAsyncQueryProvider?

时间:2019-09-06 15:21:19

标签: c#

我正在使用以下链接在x单元中模拟FromSql方法 How could I Mock the FromSql() method?

使用FirstOrDefaultAsync

的方法出现以下错误
  

IQueryable源的提供程序未实现   IAsyncQueryProvider。仅实现IAsyncQueryProvider的提供程序   可以用于Entity Framework异步操作。

但是对于ToListAsync方法来说,它工作正常。

SpAsyncEnumerableQueryable<Model> models = new SpAsyncEnumerableQueryable<Model>();
models.Add(new Model { ItemId = 1 });

MyDbContext.Model = MyDbContext.Model.MockFromSql(models);

下面是实际方法c#

return await this.MyDbContext.Model
    .FromSql("TestProc", 1, 1)
    .FirstOrDefaultAsync()
    .ConfigureAwait(false);

FirstOrDefaultAsync处出错

  

IQueryable源的提供程序未实现   IAsyncQueryProvider。仅实现IAsyncQueryProvider的提供程序   可以用于Entity Framework异步操作。

2 个答案:

答案 0 :(得分:0)

使用ToListAsyncFirstOrDefaultasync尝试以下步骤,看看是否可以解决该问题:

//1 - create a List<T> with test items
var users = new List<UserEntity>()
{
  new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")},
  ...
};

//2 - build mock by extension
var mock = users.AsQueryable().BuildMock();

//3 - setup the mock as Queryable for Moq
_userRepository.Setup(x => x.GetQueryable()).Returns(mock.Object);

//3 - setup the mock as Queryable for NSubstitute
_userRepository.GetQueryable().Returns(mock);

我希望这对您有帮助

答案 1 :(得分:0)

异常消息告诉您问题,FromSql返回的序列提供程序未实现IAsyncQueryProvider。您的FromSql模拟设置需要返回一个具有IAsyncQueryProvider提供程序的序列。

我认为您可以采用几种方法。一种是创建自己的实现IAsyncQueryProvider的AsyncQueryProvider,然后确保FromSql模拟调用返回将其设置为提供程序的序列。这将带您实现同时实现IAsyncEnumerator和IAsyncEnumerable的类。

另一个可行的方法是在设置FromSql模拟时,将返回序列转换为Queryable,然后转换为AsyncEnumerable。在我的头顶上看起来像enumerable.AsQueryable().ToAsyncEnumerable()。这是我目前在设置DbQuery模拟时所做的,并且似乎可以支持异步LINQ操作。

话虽如此,但在EntityFrameworkCore.Testing中做到了这一点(它在FromSql调用的基础上确实支持FirstOrDefaultAsync),为您节省了一些时间,并使用其中一个为您提供帮助的库。

[Test]
public virtual async Task FromSqlThenFirstOrDefaultAsync_ReturnsFirstElement()
{
    var storedProcedureReturns = Fixture.CreateMany<TestEntity>().ToList();
    var mockedDbContext = 
        Create.MockedDbContextFor(new TestDbContext(new DbContextOptionsBuilder<TestDbContext>().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options));
    mockedDbContext.Set<TestEntity>().AddFromSqlResult("usp_SomeStoredProcedure", storedProcedureReturns);

    var actualResult = await mockedDbContext.Set<TestEntity>().FromSql("[dbo].[usp_SomeStoredProcedure] @Parameter1, @Parameter2").FirstOrDefaultAsync();

    Assert.That(actualResult, Is.EqualTo(storedProcedureReturns.First()));
}