I’ve spent the past few days looking at (and in some ways implementing) unit and integration testing in Entity Framework 4. In this article I am going to talk about unit testing.
So for those currently researching the same topic, I figured I would save you some time and compile my thoughts on the matter. I’m going to add a disclaimer here: this is what I have found from my research. This is not a definitive solution to the process; in fact, I am not proposing a solution at all. I am instead going to critique the current proposed solution, and also voice my frustration about the ‘improved testability’ of the entity framework.
So I am sure if you have googled the issue you may have come across posts like these. They all propose the same solution: have our generated context implement an interface (We will call it IEntityContext) which exposes IObjectSets for each set of entities in our model, and possible a Save method as well. This way, we can create a fake or mock context backed by in-memory collections which we can test against. We can use this context to perform basic CRUD operations on POCO entities.
Then, according to the pattern given in the above links, and also in a number of textbook’s I have read, we can create an IRepository interface to hold our IEntityContext (or whatever you would like to name it), and use generics to type the repository to an Entity and off I go merrily into the sunset with only add, remove, delete and get methods typed to a single type, designing my application which attaches orders to customers, or perhaps displays a list of books or movies! </sarcasm>
Okay, so the application I am trying to work this into has around 80 or so entities. Do I want a repository for each of these? Probably not. At the very least I would need a strong justification for all of this boiler-plate. I also need to use these entities together in various arrangements, not in isolation. The suggested practice is to then wrap these repositories in ‘Units of work’ (http://martinfowler.com/eaaCatalog/unitOfWork.html) which lets us combine the necessary Repositories in a single receptacle to perform work via our application. So, more boiler-plate. In an ideal solution I would probably like to be able to combine both of these patterns.
So the solutions analysed above have the following pro’s and con’s:
· Simple methods mean simple tests.
· Fully testable.
· Good separation of concerns.
· Tonnes of boiler-plate code.
· Inability to use a lot of Entity Frameworks provided features (discussed below).
· Inelegant solution.
So for me, the cons are pretty heavy here, and none weigh down more than the restriction of code necessary to implement this solution. Let me elaborate. Your IEntityContext (or whatever you called it), can only use CRUD operations and linq expressions for queries. You want change tracking that is given to you when you instantiate POCO entities using ObjectContext.CreateObject<T>? Too bad, you’ll have to implement your own change analysis and tracking, because you can’t use the supplied proxies with this solution. Want to improve the speed of certain repositories by setting their ObjectSet’s MergeOption parameter to NoTracking where applicable? Nope, you can’t do that either.
I would run down all the other things you miss out on too, but essentially it just boils down to the fact that by attempting to Mock ObjectContext and ObjectSet (The very basis of the testability implemented above), you greatly restrict the features of the Entity Framework you can use.
So they may have improved the testability of the Entity Framework from ‘nigh on untestable’ to ‘somewhat testable in a limited state’, but I still don’t think this is a particularly good result.
I am just about to go out and see if TypeMock, or RhinoMock or any other mocking framework has the ability to isolate the ObjectContext’s methods without attempting to manually mock the whole thing. Fingers crossed! (If I find a decent solution, I will be sure to post about it soon!)
Edit: For those wanting to use this solution anyway (I’m sure it would be suitable for some), there is great T4 template to generate your interface and Mock context automatically created by Rab Hallett, and you can access it directly via VS 2010 as described here.
| posted on Sunday, 12 September 2010 1:47 PM