The provider for the source IQueryable doesn't implement IAsyncQueryProvider

后端 未结 4 1807
执念已碎
执念已碎 2020-12-02 01:50

I have some codes like below, I want to write unit tests my method. But I\'m stuck in async methods. Can you help me please ?

public class Panel
{
    publi         


        
相关标签:
4条回答
  • 2020-12-02 02:06

    When querying for panel, removing the async in firstordefault.

    Also remove the async from tolist when querying for analytics

    0 讨论(0)
  • 2020-12-02 02:07

    You could implement an AsyncEnumerable which can be used like this:

    private readonly IQueryable<Panel> panels = new AsyncEnumerable(new List<Panel>() 
    {
        panel
    });
    

    Here is the implementation of it:

    public class AsyncEnumerable<T> : EnumerableQuery<T>, IAsyncEnumerable<T>, IQueryable<T>
    {
        public AsyncEnumerable(IEnumerable<T> enumerable) : base(enumerable) { }
    
        public AsyncEnumerable(Expression expression) : base(expression) { }
    
        public IAsyncEnumerator<T> GetEnumerator()
        {
            return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
        }
    
        IQueryProvider IQueryable.Provider => new AsyncQueryProvider<T>(this);
    }
    

    The AsyncEnumerator class:

    public class AsyncEnumerator<T> : IAsyncEnumerator<T>
    {
        private readonly IEnumerator<T> _inner;
    
        public AsyncEnumerator(IEnumerator<T> inner)
        {
            _inner = inner;
        }
    
        public void Dispose()
        {
            _inner.Dispose();
        }
    
        public T Current => _inner.Current;
    
        public Task<bool> MoveNext(CancellationToken cancellationToken)
        {
            return Task.FromResult(_inner.MoveNext());
        }
    }
    

    The AsyncQueryProvider class:

    public class AsyncQueryProvider<TEntity> : IAsyncQueryProvider
    {
        private readonly IQueryProvider _inner;
    
        internal AsyncQueryProvider(IQueryProvider inner)
        {
            _inner = inner;
        }
    
        public IQueryable CreateQuery(Expression expression)
        {
            return new AsyncEnumerable<TEntity>(expression);
        }
    
        public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
        {
            return new AsyncEnumerable<TElement>(expression);
        }
    
        public object Execute(Expression expression)
        {
            return _inner.Execute(expression);
        }
    
        public TResult Execute<TResult>(Expression expression)
        {
            return _inner.Execute<TResult>(expression);
        }
    
        public IAsyncEnumerable<TResult> ExecuteAsync<TResult>(Expression expression)
        {
            return new AsyncEnumerable<TResult>(expression);
        }
    
        public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
        {
            return Task.FromResult(Execute<TResult>(expression));
        }
    }
    
    0 讨论(0)
  • 2020-12-02 02:17

    I get stuck on this issue today and this lib resolve it for me https://github.com/romantitov/MockQueryable completely, please refer:

    Mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc.

    //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);
    
    0 讨论(0)
  • 2020-12-02 02:28

    This is because of your mocking approach; your mock provider just returns panels for Query, and panels is a simple object with LINQ-to-Objects exposing it as queryable:

    private readonly IQueryable<Panel> panels = new List<Panel>() { panel }.AsQueryable();
    

    Indeed, this does not implement IAsyncQueryProvider. If you can get hold of the regular query provider, you should be able to wrap that with a fake always-synchronous version to spoof it (just use return Task.FromResult(Execute(expression))), but frankly I'm not sure that this would be a useful test... at that point you're skipping so many of the important realities of async that it probably isn't worth it.

    0 讨论(0)
提交回复
热议问题