Mocking, with NSubstitute, entity framework FirstOrDefualtAscync method throws exception

c# entity-framework entity-framework-6 nsubstitute

Question

I am trying to write unit test by mocking. My test is mocking the GetAll method which is using FirstOrDefaultAsync method. If I change FirstOrDefaultAsync to FirstOrDefault my test works fine but it keeps failing when I put back FirstOrDefaultAsync.

My unit test code is below

[TestMethod]
public async Task GetAsync_WithUser_ReturnsOk()
{
    var data = GetUserResult();

    var mockContext = Substitute.For<IPostAnythingContext>();
    var mockSet = data.GenerateMockDbSetForAsync();
    mockContext.Users.Returns(mockSet);

    uow.User.GetAll().Returns(data);
    var result = await sut.GetAsync("a@a.com");
}

Code I am trying to test

public async Task<Result<Users>> GetAsync(string email)
{
    var result = Uow.User.GetAll()
                .Where(x => x.EmailAddress == email)
                .Include(x => x.UsersUsersTypes);
    return Result.Ok(await result.FirstOrDefaultAsync());
}

My extension method

public static DbSet<TEntity> GenerateMockDbSetForAsync<TEntity>(this IEnumerable<TEntity> queryableEnumerable) where TEntity : class
    {
       var queryable = queryableEnumerable as IQueryable<TEntity> ??      queryableEnumerable.AsQueryable();

       var mockSet = Substitute.For<DbSet<TEntity>, IQueryable<TEntity>, IDbAsyncEnumerable<TEntity>>();

                    // async support
     var castMockSet = (IQueryable<TEntity>)mockSet;
     var castAsyncEnum = (IDbAsyncEnumerable<TEntity>)mockSet;
         castAsyncEnum.GetAsyncEnumerator().Returns(new TestDbAsyncEnumerator<TEntity>(queryable.GetEnumerator()));
         castMockSet.Provider.Returns(new TestDbAsyncQueryProvider<TEntity>(queryable.Provider));

       castMockSet.Expression.Returns(queryable.Expression);
       castMockSet.ElementType.Returns(queryable.ElementType);
       castMockSet.GetEnumerator().Returns(queryable.GetEnumerator());
       return mockSet;
    }

Exception I am getting

Test Name: GetAsync_WithUser_ReturnsOk
Test FullName: PostAnything.Business.Tests.UsersServiceTests.GetAsync_WithUser_ReturnsOk
Test Source: C:\TFS\PostAnything\PostAnything.Business.Tests\UsersServiceTests.cs : line 40
Test Outcome: Failed
Test Duration: 0:00:02.5118084

Result StackTrace:

at System.Data.Entity.QueryableExtensions.FirstOrDefaultAsyncTSource
at System.Data.Entity.QueryableExtensions.FirstOrDefaultAsyncTSource
at PostAnything.Business.Implementation.UsersService.d__2.MoveNext() in C:\TFS\PostAnything\PostAnything.Business\Implementation\UsersService.cs:line 28
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at PostAnything.Business.Tests.UsersServiceTests.d__5.MoveNext() in C:\TFS\PostAnything\PostAnything.Business.Tests\UsersServiceTests.cs:line 49
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
Result Message: 
Test method PostAnything.Business.Tests.UsersServiceTests.GetAsync_WithUser_ReturnsOk threw exception: 
System.InvalidOperationException: The provider for the source IQueryable doesn't implement IDbAsyncQueryProvider. Only providers that implement IDbAsyncQueryProvider can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
1
0
10/15/2016 8:21:46 AM

Popular Answer

In order to mock asynchronous queries you need to implement IDbAsyncQueryProvider interface. I don't know how do you implement GenerateMockDbSetForAsync method but here is complete toturial on mocking async methods.

Testing with a mocking framework (EF6 onwards)

Testing with your own test doubles (EF6 onwards)

0
10/15/2016 7:25:48 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow