Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DbSet mock, no results while calling ToList secondly

Tags:

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); 
like image 850
Emil Jasiński Avatar asked May 04 '14 19:05

Emil Jasiński


2 Answers

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() ); 
like image 122
Wiktor Zychla Avatar answered Oct 02 '22 08:10

Wiktor Zychla


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

like image 40
Kelu Thatsall Avatar answered Oct 02 '22 09:10

Kelu Thatsall