How EF6 Enables Mocking DbSets more easily

There’s an interesting change in EF6 that simplifies unit testing when EF is in the way and you don’t want to engage it at all.

EF6 DbSet gained new features. The team had to decide if they would make a breaking change to the existing IDbSet interface or leave that be and just change DbSet. They chose

the latter route. In doing so, they also ensured that we could use the DbSet directly for testing by adding a new constructor.

Here’ you can see the different constructors and how they affect our ability to test.

EF5 DbSet Constructor

The DbSet constructor is tied to a DbContext by way of the InternalQuery that is used internally in the constructor.

internal DbSet(InternalSet<TEntity> internalSet)
   : base((IInternalQuery<TEntity>) internalSet)
 {
   this._internalSet = internalSet;
 }

In  EF5, we also have IDbSet (DbSet derives from this) (and IObjectSet which was introduced in EF4) . These interfaces contain the set operations (Add, Update, Remove and some additional methods through other interfaces) and can be implemented without forcing any ties to EF’s DbContext.

That’s what we’ve used in the past to create fake DbSets for testing scenarios.

EF6 DbSet Constructors

The internal constructor is still there.

    internal DbSet(InternalSet<TEntity> internalSet)
      : base((IInternalQuery<TEntity>) internalSet)
    {
      this._internalSet = internalSet;
    }

But now there is another constructor. It’s protected and only uses an set interface, but not the query interface. This allows mocking frameworks to get access to DbSet and at the same time, benefit from some of the methods added to DbSet for EF6.

 

  /// <summary>
  /// Creates an instance of a <see cref="T:System.Data.Entity.DbSet`1"/> when called from the constructor of a derived
  ///             type that will be used as a test double for DbSets. Methods and properties that will be used by the
  ///             test double must be implemented by the test double except AsNoTracking, AsStreaming, an Include where
  ///             the default implementation is a no-op.
  /// 
  /// </summary>
  protected DbSet()
    : this((InternalSet<TEntity>) null)
  {
  }

Even if you wanted to create your own fakes (or test doubles) in EF6, you can do that with DbSet now, not IDbSet. IDbSet is still there for backwards compatibility.

There are two detailed documents on MSDN for using EF6 to create Test Doubles and to use with Mocking Frameworks.

You also might find the meeting notes about this change interesting. I sure do! :)

I am curious to revisit my work with Telerik’s JustMock. I built some tests with EF5 and JustMock in my Automated Testing for Fraidy Cats course on Pluralsight. When using the paid version, everything just works. But when using JustMock Lite, the free version, it was not able to grok DbSets and you still needed to implement your own fake. I’ll be checking to see if the new DbSet implementation allows the free version of JustMock to mock DbSets on it’s own now.

//update about 20 minutes after initial post. The limitation of JustMock Lite is that it doesn’t support ReturnsCollection which is what you want to emulate the return of a DbSet. So if you’re not willing to pay for your tools, you can use the free version (which has a ton of features) and do a little extra work (create your own test double for DbSet which you can see how to do in MSDN doc I linked to above.

11 thoughts on “How EF6 Enables Mocking DbSets more easily

  1. Hi,

    I am facing issue with SqlFunctions.StringConvert method. It seems like it doesnot work after after EF-6 upgade. And it is working fine in previous version. Should i change the namespace or something?

    exception:
    LINQ to Entities does not recognize the method ‘System.String StringConvert(System.Nullable`1[System.Double])’ method, and this method cannot be translated into a store expression.

    Thanks

    1. Hi Sreekanth,
      Yes it’s a namespace change. EF classes/namespaces that were in System.Data (but not under System.Data.Entity) moved.

      The SqlFunctions were in System.Data.Objects.SqlClient.SqlFunctions.

      They are now in System.Data.Entity.SqlServer.SqlFunctions.

  2. Great info! Julie, how would your implementation of the code in your Pluralsight course “Entity Framework in the Enterprise” simplify if re-tooled for EF6 to take advantage of this? Any details would be mundo appreciated.

    1. I am starting to think that when I get the DDD and EF6 courses done, I will do a new version of the enterprise course. WRT the Mocking DBSets, I would get rid of the fake implementations and just use mocking. I would probably still demonstrate how to create fakedbsets etc for folks who just don’t want to use a mocking framework.

  3. Hi,
    Thanks for the article and thanks for great Pluralsight courses. I’m trying to test with Async queries using Moq, anything that uses .ToListAsync works but .FirstOrDefaultAsync throws an error: The member ‘IQueryable.Provider’ has not been implemented on type ‘DbSet`1Proxy_1′ which inherits from ‘DbSet`1′.

    Any thoughts, thanks

    1. sorry I don’t know. :( A quick google search led me nowhere. Maybe try asking on stackoverflow? If you find the answer, would you mind adding a link here for any others that find this comment when searching the same problem. Thanks!

Leave a Reply

Your email address will not be published. Required fields are marked *


+ three = 9

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>