Sunday 27 February 2011

Mocking DbContext Entity Framework 4 Code First CTP5 with NSubstitute

Take an Entity Framework 4 Code First model, something like this:

   1: public class Customer
   2: {
   3:    public int Id { get; set; }
   4:    public string Name { get; set; }
   5: }
   6:  
   7: public class CustomerContext : DbContext, ICustomerContext
   8: {
   9:    public DbSet<Customer> Customers { get; set; }
  11: }


I now want to write some tests and I'm going to mock the DbContext using NSubstitute.  I first try something like this:

   1: [Test]
   2: public void can_mock_customer_context()
   3: {
   4:    var context = Substitute.For<CustomerContext>();
   5:    context.Customers.Returns(
   6:       new DbSet<Customer>(
   7:          new[]
   8:          {
   9:             new Customer {Name = "Sean"}
  10:          })
  11:       );
  12:    Assert.AreEqual(1, context.Customers.Count());
  13: }

The problem is that the DbSet constructor is internal (as of EF4 Code First CTP5).  So, let's abstract our DB access to a simple interface and replace DbSet<T> with the IQueryable<T> interface, ending up with the below:

   1: public interface ICustomerContext
   2: {
   3:    IQueryable<Customer> Customers { get; set; }
   4: }

This interface can be implemented like so:

   1: public class CustomerContext : DbContext, ICustomerContext
   2:   {
   3:      public DbSet<Customer> Customers { get; set; }
   4:      IQueryable<Customer> ICustomerContext.Customers { get { return Customers; } }
   5:   }

Now all we need to do is to use an implementation of IQueryable<T> in our mock.  I'm going to use EnumerableQuery<T> which gives me the following test that now passes:

   1: [Test]
   2: public void can_mock_customer_context()
   3: {
   4:    var context = Substitute.For<ICustomerContext>();
   5:    context.Customers.Returns(
   6:       new EnumerableQuery<Customer>(
   7:          new[]
   8:          {
   9:             new Customer {Name = "Sean"}
  10:          })
  11:       );
  12:    Assert.AreEqual(1, context.Customers.Count());
  13: }
  14:    }

I'm new to NSubstitute but it seem to be the lowest friction mocking library out there.  Just perfect for use with Entity Framework 4 Code First - certainly the lowest friction ORM there is today!

Note that we could have used the repository pattern to wrap the DbContext instead of a simple interface, the approach is almost identical.

Update: Ro Miller has an alternative approach using fakes that does a better job of surfacing IDbSet.  Check it out here: http://romiller.com/2010/09/07/ef-ctp4-tips-tricks-testing-with-fake-dbcontext/.

Thursday 17 February 2011

Package Manager With Source Download

I was skinning up some code and I used my package manager of choice to add NLog to the project.  All good, very easy and away I coded.

The project required a single DLL as an output.  So, I thought hey – I’ll use Paul Stovell’s Tape to save using ILMerge in the build.  Good plan, but after 5 minutes browsing the NLog source on GitHub it realised I was not sure how to find the version I needed.  That’s fine, ILMerge is pretty easy to use so I used the build to save the day.

On the same day (today) I read this post about ReSharper 6 features and suddenly realised how powerful it would be for package managers to be able to give me the source, not just binaries.  Now that’s a killer feature and would be even better if the source came with a single file option so I didn’t even have to run Tape.

Oh, please, soon…

Thursday 3 February 2011

A Better Deal

Red Gate are now going to charge for Lutz Roeder’s Reflector.  This tool has been free for it's life – more years than I care to remember.  Its as much part of a software developer’s toolkit as a hammer is part of a builder’s toolkit.

I have dealt with Red Gate as part of a very small company and as part of a very large company.  I am sorry to say that each time I have come away feeling less than happy.  Any company that sends be a maintenance bill at the end of year one that exceeds my original purchase price isn't going to make me happy to deal with them!

Reading Red Gates’ pricing strategy, written by their co-founder, Neil Davidson, I struggle to believe their other CEO, Simon Galbraith, when he says how sorry he is about charging for Reflector.  I just kept thinking that they just want my cash - like the other times I’ve dealt with them.

Maybe Galbraith and Davidson should go and listen to Seth Godin’s pricing advice.  Maybe then I’d want to buy stuff from them! 

35USD is good value for Reflector and I may have to buy a copy.  I’d really just rather buy from another company and get a better deal.