Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extension methods of Entity Framework in unit test using Moq and Autofac

I'm mocking a DbSet from Entify Framework. I want to use its extension method ToListAsync. This is how I do it and below a result of my attempt (regular 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 has value as expected. But the variable testAsync has value like this:

test ToListAsync result

When I uncomment the part where I try to setup ToListAsync 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>()"}

I'd appreciate any suggestions. Should I switch to Fakes maybe? is such functionality supported there?

like image 807
Kelu Thatsall Avatar asked Dec 09 '25 21:12

Kelu Thatsall


1 Answers

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 use of C#6 shorthand features):

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 root cause of the error is that Moq cannot mock static methods, at least for now.

like image 109
Sean B Avatar answered Dec 12 '25 05:12

Sean B



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!