r3plica
r3plica

Reputation: 13387

The source IQueryable doesn't implement IDbAsyncEnumerable when trying to mock

I am trying to test a bit of code I have:

public async Task<Sortation> SaveAsync(Sortation sortation)
{
    if (sortation.Id == 0)
    {
        var sortations = await ListAsync(sortation.CategoryId);
        sortation.Order = sortations.Count;
        _sortationService.Create(sortation);
    }
    else
    {
        _sortationService.Update(sortation);
    }

    await _sortationService.SaveChangesAsync();

    return sortation;
}

The ListAsync method is causing me an issue. I set up my test like this:

[Test]
public async Task ShouldHaveOrderOfZero()
{
    // Assemble
    const string categoryId = "cameras";
    var services = SortationContext.GivenServices();
    var sortationProvider = services.WhenGetSortationProvider();
    var sortations = new List<Sortation>();
    var sortation = new Sortation { CategoryId = categoryId };

    services.MockSortationService.Setup(x => x.List()).Returns(sortations.AsQueryable);

    // Act
    await sortationProvider.SaveAsync(sortation);

    // Assert
    sortation.Order.Should().Be(0);
}

And when I run this, I get this error:

Message: System.InvalidOperationException : The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations.

According to this: Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations I need to add EF to my UnitTest project, which I did. But the error still persists.

The ListAsync method looks like this:

public async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) => 
    await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();

Does anyone know how I can stop this error from happening?

Upvotes: 3

Views: 6779

Answers (2)

Navid Developer
Navid Developer

Reputation: 221

In my case the exception was caused by using the wrong ToListAsync extension.

It came from:

using System.Data.Entity; instead of

using Microsoft.EntityFrameworkCore; Changing the namespace fixed the error.

Upvotes: 22

KozhevnikovDmitry
KozhevnikovDmitry

Reputation: 1720

Don't know if question is still actual, but still. I agree with Mark's comment, however here is an example, that works for me. I added some reasonable stub implementation for mentioned class, because there are not enouch details in question. I can be wrong in my assumptions:

[Test]
public async Task ShouldHaveOrderOfZero()
{
    // Assemble
    const string categoryId = "cameras";
    var services = SortationContext.GivenServices();
    var sortationProvider = services.WhenGetSortationProvider();
    var sortations = new List<Sortation>();
    var sortation = new Sortation { CategoryId = categoryId };

    // the key moq configuration here
    services.MockSortationService.Setup(x => x.ListAsync(It.IsAny<string>())).Returns(Task.FromResult(sortations));

    // Act
    await sortationProvider.SaveAsync(sortation);

    // Assert
    sortation.Order.Should().Be(0);
}

public class SortationProvider
{
    private SortationService _sortationService;

    public SortationProvider()
    {
        _sortationService = new SortationService();
    }

    public async Task<Sortation> SaveAsync(Sortation sortation)
    {
        if (sortation.Id == 0)
        {
            var sortations = await ListAsync(sortation.CategoryId);
            sortation.Order = sortations.Count;
            _sortationService.Create(sortation);
        }
        else
        {
            _sortationService.Update(sortation);
        }

        await _sortationService.SaveChangesAsync();

        return sortation;
    }

    // should be virtual
    public virtual async Task<List<Sortation>> ListAsync(string categoryId, params string[] includes) =>
        await _sortationService.List(includes).Where(m => m.CategoryId.Equals(categoryId)).ToListAsync();

}

public class SortationContext
{
    public static Services GivenServices()
    {
        return new Services();
    }
}

public class Services
{
    public Services()
    {
        MockSortationService = new Mock<SortationProvider>();
    }

    public SortationProvider WhenGetSortationProvider()
    {
        return MockSortationService.Object;
    }

    public Mock<SortationProvider> MockSortationService { get; set; }
}

internal class SortationService
{
    public void Create(Sortation sortation)
    {

    }

    public void Update(Sortation sortation)
    {

    }

    public Task SaveChangesAsync()
    {
        return Task.CompletedTask;
    }

    public DbSet<Sortation> List(string[] includes)
    {
        throw new NotImplementedException();
    }
}

public class Sortation
{
    public string CategoryId { get; set; }
    public int Id { get; set; }
    public int Order { get; set; }
}

The main change is in line that contains Setup method. I made ListAsync method virtual also. The main assumption is that List(string[] includes) method returns DbSet<Sortation>. Hope it helps.

Upvotes: 0

Related Questions