FakeItEasy DbSet / IQueryable - Entity Framework 6

dbcontext dbset entity-framework-6 fakeiteasy unit-testing

Question

I was wondering if anyone had a similar example to this post for FakeItEasy (original post is here. I have been trying to find the correct setup, but could not get it right. I could not find any examples online. I am beginning to teach myself unit testing and I decided to use FakeItEasy. All my projects so far use the entity framework and do not use the Repository/UOW pattern since I consider DbSet and DbContext good enough for my small scale applications. I understand there are pros/cons with EF and unit testing, but I would still like to figure this out. I am pretty sure I am way off with my attempt (see below) since the error I get is

System.NotImplementedException: The member 'IQueryable.Provider' has not been implemented on type 'DbSet1Proxy' which inherits from 'DbSet1'. Test doubles for 'DbSet`1' must provide implementations of methods and properties that are used.

Any direction will be very helpful. Thank you.

var data = new List<Request> 
{ 
request1, 
request2, 
request3
}.AsQueryable();

var fakeDbSet = A.Fake<DbSet<Request>>();

A.CallTo(() => ((IQueryable<Request>)fakeDbSet).Provider).Returns(data.Provider);
A.CallTo(() => ((IQueryable<Request>)fakeDbSet).Expression).Returns(data.Expression);
A.CallTo(() => ((IQueryable<Request>)fakeDbSet).ElementType).Returns(data.ElementType);
A.CallTo(() => ((IQueryable<Request>)fakeDbSet).GetEnumerator()).Returns(data.GetEnumerator());

var fakeContext = A.Fake<RequestPortalContext>();
A.CallTo(() => fakeContext.Requests).Returns(fakeDbSet);

var service = new RequestReadService(fakeContext);
var requests = service.GetAllRequests();

Assert.AreEqual(3, requests.Count);
Assert.AreEqual("Test1", requests[0].Name);
Assert.AreEqual("Test2", requests[1].Name);
Assert.AreEqual("Test3", requests[2].Name);
1
3
5/23/2017 11:53:05 AM

Accepted Answer

I'm not familiar with EntityFramework at all, and can't say what's going on for sure, since there's no stack trace with the NotImplementedException, but here's my guess:

You're seeing the exception raised from either the line that defines service or the one that calls GetAllRequests, not the A.Fake<DbSet<Request>>() line.

It sounds to me like the innards of RequestReadService (is that your class, I can't find it elsewhere?) or something it calls relies on the DbSet also implementing IQueryable.Provider. Now. I'm not sure why that wouldn't already be present. Perhaps it's the explicit implementation that throws it off. The best I can suggest (and I've not tried this, given my complete lack of EF6 knowledge), is to maybe try explicitly adding the interface to the fake:

A.Fake<DbSet<Request>>(builder => 
                         builder.Implements(typeof (IQueryable<Result>)));

Although after I typed that, I read FakeItEasy issue 31, which I fear may apply, and so my idea may not work. Then again, if you're willing, give it a go. It may not take long.

Alternatively, in the short term, I'm not sure what other workarounds to suggest. Perhaps faking some of the interfaces that DbSet implements instead of faking DbSet itself?

Updated: after another question about this kind of thing, and actually grabbing EF6 so I could try it out, I created Issue 477 to track what appears to be the underlying problem here.

7
4/8/2015 2:31:11 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow