locked
Building an EF in-memory object provider for testing. RRS feed

  • Question

  • One pain point I've run across using the Entity Framework is in creating testable code. I know this has been an issue for others here as well.

    One suggestion to alleviate testing issues has been to put all data access behind a repository class so we can stub out a test repository with data. I think this is reasonable, yet I also believe this limits the usefulness of the EF model. I'd much rather query my data context object directly than go through another layer of code. I believe it was the EF team itself that said they envision the data context as being a repository itself.

    I realized what I really need is a data context that is backed by an in-memory data store that I can populate and pass around while testing. What would be involved in creating such a thing? I know the EF can hook into different databases, so shouldn't an in-memory object-based solution work?

    Here's what I envision:

    Given a service-layer class that takes a DataContext object:

    Code Snippet

    public class MyService {

     
      protected DataContext MyDataContext { get; set; }

      public MyService(DataContext dataContext) { MyDataContext = dataContext;  }

      public PromoteEmployee(int employeeId) {
        var employee = MyDataContext.Employees.Where(e => e.EmployeeId== employeeId).First();
        employee.Level += 1;
        MyDataContext.Save();
      }
    }


    It would be great if the DataContext that was passed in the constructor could be swapped out at testing time for one backed by an in-memory object store that was populated with employees already. This would be suitable for testing since no DB would be needed.

    What would be involved in building something like this? This would be extremely useful and I'd be willing to contribute some time to work on such a project on Codeplex.
    Friday, November 14, 2008 7:56 PM

Answers

  •  

    Hi Brian -

     

    Why do you say you need an in-memory store?  Would using a sql ce database be sufficient?

     

    Writing an EF provider is not a small amount of work.  A provider already exists for sql ce, so hopefully that will suit your needs. 

     

    An alternative might be to use a mocking framework.  This should be possible to do today, but will be made easier with the next release of the EF and its support for persistent-ignorant objects (aka "POCO").

     

    Thanks,

     

    Mike & Noam

    Microsoft

     

     

    Friday, November 14, 2008 10:20 PM

All replies

  •  

    Hi Brian -

     

    Why do you say you need an in-memory store?  Would using a sql ce database be sufficient?

     

    Writing an EF provider is not a small amount of work.  A provider already exists for sql ce, so hopefully that will suit your needs. 

     

    An alternative might be to use a mocking framework.  This should be possible to do today, but will be made easier with the next release of the EF and its support for persistent-ignorant objects (aka "POCO").

     

    Thanks,

     

    Mike & Noam

    Microsoft

     

     

    Friday, November 14, 2008 10:20 PM
  •  Mike Kaufman - MSFT wrote:

     

    Hi Brian -

     

    Why do you say you need an in-memory store?  Would using a sql ce database be sufficient?

     



    I've never considered SQL Compact before. It's an interesting idea, but I suppose breaks the true definition of a unit test. I thought of an in-memory provider simply because it would be very fast, and could be reset instantly. SQL Compact obviously won't be quite as fast, and I'm not sure how quickly I could reset the data between tests. It may still prove useful if there's no other way to go.

    As for mocking, it's something I already do for other testing components, but what I'm really after here is a "fake" DataContext. Or rather a real DataContext backed by a fake DB. I'm not sure how to mock the DataContext such that a component which runs a LINQ query will provide a certain result.

    Looking forward to V2!
    Friday, November 14, 2008 11:27 PM
  • I wonder what the point is in testing your ObjectContext without a backing database?

     

    Wouldn't the point of tests that go against the context be to ensure that you are issuing the right queries and getting the expected results? Is speed of setup/teardown the concern here? If it is, you could always use SQL CE, create a .SDF file with your database, copy it at the start of the test, and work against the copy, then delete the modified .SDF copy at the end of the test...or you could just write a simple setup/teardown script that goes against the database using pure TSQL...lots of options.

    Saturday, November 15, 2008 12:38 AM
  • The point is not to test the data context (at least that's not what I'm trying to test) -- the point is to isolate and test a service layer that does something with data that happens to be retrieved by the data context. So what I want is:

    1) Start with known data backing a context.
    2) Run some service layer code that interacts with the data via a context.
    3) Check output of service and data to ensure they are in the expected state.

    My concern was the speed of setup/teardown. I started looking into using SQL CE and found about half a dozen incompatibilities with my schema. I think they might all be trivial to change however (eg. char -> nchar).

    I'll report back later this week after I have had a bit more time to work this out.

    Tuesday, November 18, 2008 5:14 AM
  • Hey Brian,

    Did u get any solution to create fake data context for nunit testing.

    Regards,
    Puneet
    Tuesday, November 17, 2009 10:12 AM
  • I think the current semi-official recommendation is to create a repository layer and mock the repositories. The alternative of using SQL CE for testing is also fairly reasonable, but really, mocking the context seems a bit odd - one wants mocking to occur at system boundaries, so unless you use the context itself as a very coarse grained repository, there doesn't seem to be much of a point.
    This posting is provided "AS IS" with no warranties, and confers no rights.
    Friday, November 20, 2009 7:46 PM