I'm trying to mock DbContext and DbSet. This works for my previous unit tests, but problem occurs while my code was calling ToList method on DbSet second time.
First dbSet.ToList() returns mocked results. Second one returns 0 elements;
var queryableData = new List<string>{ "a", "b", "c" }.AsQueryable(); var mockDbSet = new Mock<DbSet<string>>(); var q = mockDbSet.As<IQueryable<string>>(); q.Setup(m => m.Provider).Returns(queryableData.Provider); q.Setup(m => m.Expression).Returns(queryableData.Expression); q.Setup(m => m.ElementType).Returns(queryableData.ElementType); q.Setup(m => m.GetEnumerator()).Returns(queryableData.GetEnumerator()); DbSet<string> dbset = mockDbSet.Object; IQueryable<string> query = dbset; //RESULTS: abc var a1 = dbset.ToList(); foreach (var a in a1) Console.Write(a); //NO RESULTS var a2 = dbset.ToList(); foreach (var a in a2) Console.Write(a);
You return the very same enumerator instance upon each call to GetEnumerator
. When it enumerates once, it is done, EF doesn't call its Reset
method, rather it asks for a new enumerator.
But you return the one that just has yielded all elements and yields no more.
Instead, return a function that returns the enumerator, that will return a new enumerator each time you ask for it.
q.Setup(m => m.GetEnumerator()).Returns( () => queryableData.GetEnumerator() );
I just wanted to added to Wiktor Zychla's answer my little part. If someone is looking for Async version of this mock (coming from this tutorial: http://msdn.microsoft.com/en-us/data/dn314429.aspx#async) then this is my modification to TestDbAsyncEnumerator<T>
class:
internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> { private readonly IEnumerator<T> _inner; public TestDbAsyncEnumerator(IEnumerator<T> inner) { _inner = inner; } public TestDbAsyncEnumerator(Func<IEnumerator<T>> valueFunction) { _inner = valueFunction(); } public void Dispose() { _inner.Dispose(); } public Task<bool> MoveNextAsync(CancellationToken cancellationToken) { return Task.FromResult(_inner.MoveNext()); } public T Current { get { return _inner.Current; } } object IDbAsyncEnumerator.Current { get { return Current; } } }
Then like Wiktor suggested you have to setup it with delegate so in case of async it would be like that:
mockSet.As<IDbAsyncEnumerable<Blog>>() .Setup(m => m.GetAsyncEnumerator()) .Returns(new TestDbAsyncEnumerator<Blog>(() => data.GetEnumerator()));
If someone wants source for that then here you go: https://github.com/kelostrada/EntityFrameworkWithMock.Test
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With