romantitov / MockQueryable

Mocking Entity Framework Core operations such ToListAsync, FirstOrDefaultAsync etc
MIT License
767 stars 74 forks source link

Not suported with EF6: BulkUpdateAsync, BulkDeleteAsync, SingleUpdateAsync. #67

Open DianaGumar opened 1 year ago

DianaGumar commented 1 year ago

Hi Guys. I use MockQueryable approach for EF async methods testing. But I've noticed that it doesn't work for async methods for collections, exactly 'bulk extensions': https://entityframework-extensions.net/bulk-update

Message:  System.AggregateException : One or more errors occurred. (Field '_queryCompiler' defined on type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider' is not a field on the target object which is of type 'TestAsyncEnumerableEfCore[TEntity]'.) ---- System.ArgumentException : Field '_queryCompiler' defined on type 'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider' is not a field on the target object which is of type 'TestAsyncEnumerableEfCore[TEntity]'.

After some investigation, I found out that Bulk extensions methods require using EntityQueryProvider as provider and IQueryCompiler as _queryCompiler field.

I use the next code to set up async EF methods for testing:

private Mock<DbSet<TEntity>> DbSetConfigureForAsync<TEntity>(Mock<DbSet<TEntity>> dbSet, IQueryable<TEntity> data)
    where TEntity : class
{
    var enumerable = new TestAsyncEnumerable<TEntity>(data);

    // Configure queryable calls
    dbSet.As<IQueryable<TEntity>>().Setup(m => m.Provider).Returns(enumerable);
    dbSet.As<IQueryable<TEntity>>().Setup(m => m.Expression).Returns(data.Expression);
    dbSet.As<IQueryable<TEntity>>().Setup(m => m.ElementType).Returns(data.ElementType);
    dbSet.As<IQueryable<TEntity>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());

    // Configure async enumerable calls
    dbSet.As<IAsyncEnumerable<TEntity>>()
        .Setup(m => m.GetAsyncEnumerator(It.IsAny<CancellationToken>()))
        .Returns(enumerable?.GetAsyncEnumerator());

    // Configure DbSet calls
    dbSet.Setup(m => m.AsQueryable()).Returns(enumerable); // alternative: _mockSet.Object
    dbSet.Setup(m => m.AsAsyncEnumerable()).Returns(CreateAsyncMock(data));

    return dbSet;
}

Thanks.

romantitov commented 7 months ago

Hello. Thanks for you contribution. Sorry for the late answer. Unfortunately I'm very busy at the moment. If you provide a pull request with fix of the issue I would be happy to include it to the next release. Please don't forget to cover the case by additional tests to minimize possibility of regressions for the future. Thanks for the understanding.