Entity Framework extension methods in unit test using Moq and Autofac

I am mocking DbSet from Entify Framework. I want to use his extension method ToListAsync

. This is how I do it and below is the result of my attempt (normal ToList

works):

IQueryable<DbUser> userData = MockedData.Instance.Users; // this is just a property to get custom IQueryable set of data for testing

var dbSetMock = new Mock<DbSet<DbUser>>();

dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.Provider).Returns(userData.Provider);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.Expression).Returns(userData.Expression);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.ElementType).Returns(userData.ElementType);
dbSetMock.As<IQueryable<DbUser>>().Setup(m => m.GetEnumerator()).Returns(userData.GetEnumerator());

/*
I've put it here so you can see how I tried to approach my problem
dbSetMock.Setup(x => x.ToListAsync())
    .Returns(Task.FromResult(userData.ToList()));
*/

var testAsync = dbSetMock.Object.ToListAsync();
var testRegular = dbSetMock.Object.ToList();

      

Results:

The variable testRegular

matters as expected. But the variable testAsync

has a value like this:

test ToListAsync result

When I uncomment the part where I am trying to set ToListAsync

in order to return anything, I get an exception like this:

{"Expression references a method that does not belong to the mocked object: x => x.ToListAsync<DbUser>()"}

      

Any suggestions would be appreciated. Should I switch to fakes? is this functionality supported?

+3


source to share


1 answer


I found and used this code with success:

dbSetMock.As<IDbAsyncEnumerable<DbUser>>()
    .Setup(m => m.GetAsyncEnumerator())
    .Returns(new AsyncEnumerator<DbUser>(userData.GetEnumerator()));

      

with the following support class (note the use of C # 6 shorthand functions):



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

      

The main reason for the error is that Moq cannot mimic static methods, at least for now.

+2


source







All Articles