It being a beautiful Sunday morning at the moment, I figured it would be as fine a time as any to compile my thoughts on the solution I have implemented to provide a testable EF4 architecture. Edit: Its not Sunday anymore :(
You may remember in a previous post that I detailed my frustrations with the Entity Framework espousing testability, and yet still being frustratingly untestable in some ways; along with giving my thoughts on the textbook solution to the problem echoing its way around the web.
I then moved on and thought perhaps I had seen the light with TypeMock Isolator, a super powerful mocking tool that I could use to mock out the fairly untestable portions of the EF4 ObjectContext. Now This still stands as a possible solution to the problem at hand, however it was not a suitable solution to me, based on the cost of the product. You get what you pay for, and since you get a lot with TypeMock, you also pay a lot.
So finally I followed a lead to a project contributed to by my friend Muhammed Mosa (who was becoming an invaluable resource in this little research project) called Shrinkr. Shrinkr is an open source MVC2 Url Shortening application, which demonstrates a number of best practices to follow when designing a multi layered EF4 application. I used this project as inspiration for the architecture I ended up implementing.
I will go over the high level detail of the architecture, and how testing can be applied to each layer:
Firstly, we will look at the back end. Data access is performed via the Repository pattern. A strongly typed IRepository<T> interface is created with basic CRUD methods, and a BaseRepository<T> class is created which implements these methods. Note that the base repository does not explicitly implement IRepository (i.e. : IRepository is not in it’s markup). We will get to this in a bit. The base repository in Shrinkr also accepts a DatabaseFactory (which generates the ObjectContext) and a QueryFactory (which is used to run predefined queries).
I will not go into the details of the DbFactory or QueryFactory – but they are automagically injected via Unity on instantiation. Another option would be to just set unity up to inject your object context if you wished to simplify things a little.
Then for each Entity type in your model that you wish to perform CRUD operations against, you define an IEntityNameRepository interface, which inherits from IRepository<EntityName>. You can then define a concrete implementation of EntityNameRepository which extends BaseRepository<EntityName> (so you can inherit its functionality), and implements IEntityNameRepository.
Now I mentioned that BaseRepository did not explicitly implement IRepository. This is because it will implement it implicitly via the concrete repository implementation. This very neat little piece of architecture gives us a fully mockable IEntityNameRepository implementation, because ALL of the functionality is exposed by the top level interface via explicit inheritance.
So by now you may be drawing parallels between the beginnings of this architecture and the ‘textbook solution’ I canned earlier. But here is the key point to this EF4 architecture: you are isolating the ObjectContext as much as possible, ensuring that the repositories have a very limited set of functionality (Queries, Add, Update, Delete). By ensuring that the repositories ONLY provide this limited set of functionality, and using a few handy methods supplied by the entity framework, we can create effective integration-type unit tests to run against the repositories. So yes, they will run against a live database (However this can be created, manipulated and then destroyed all via the EF4 libraries. More on this later).
So now our (integration) testable data access layer is complete. We have a couple of options from here, and they are all dependent on the requirements of your particular application. If you are using MVC, MVP, or even MVVM, you may just want to access your repositories to perform simple data access and queries directly from the C/V/VM, and that is all there is to it.
In a more complex architecture however, you may want to encapsulate some of the business logic in another layer to avoid over-stuffing (including too many responsibilities in) the C/V/VM – or the business logic may need to sit behind a firewall on a separate server. This is where we can use the Service pattern.
The design of each service can really be up to you. You may want slightly larger services to promote reuse, each service containing a number of repositories that you perform data access against to accomplish tasks.
There are a few steps to creating your services. Firstly you should define an interface which will expose the services functionality. This aids us in two ways. Firstly it allows our service layer to be fully mockable, to improve the testability of components that utilize it. Secondly it allows us to easily decouple it from the rest of the application if we need to move it onto a separate server and access it via a network.
Secondly, you need to decide what repositories your service is going to need to use throughout its operation. Each of these should be injected via their interface into the services constructor. You may make your services 1:1 with your repositories, or they may provide a service that combines several repositories. This is up to you (I imagine there would be all sorts of arguments thrown up for or against certain implementations of this… I’m not going to get sucked in to them at the moment however!)
Finally, each service should contain an injected reference to an implementation of the UnitOfWork pattern. This IUnitOfWork exposes a single method for us to use, Commit. The basics behind this is that the ObjectContext which Unity injects into each of your repositories for the given service should also be injected into the UnitOfWork. This way, any data manipulation performed on seperate repositories can all be committed in a single step using the unit of work (The Commit method will call SaveChanges on the ObjectContext). Beautiful!
Now we have a fully mockable, unit testable service layer. You can mock out the repositories and unit of work to perform unit tests in isolation, to prevent you needing to hit any physical data stores.
You may have been hoping for some code examples in this post, but seriously, just download Shrinkr and take a look – it is a good source of inspiration!
So, to summarize the above. This architecture obviously isn’t perfect, as it still houses and makes use of the somewhat untestable ObjectContext. However this is a necessary evil if you want to work with EF4. What it does do is dictate the allowable interactions with the ObjectContext in such a way as to ensure we can write effective integration tests against it, while guarding against letting other functionality sneak in that would be more difficult to test.
With this we achieve a nice separation of concerns between the layers of our application, and also allow for 100% testability. As usual it is up to the developers to ensure that the separation of concerns remains clean and intact.
For future research, I am going to investigate the possibility of mocking out ObjectContext behaviours with Telerik JustMock, since I have access to it
. Now that would be the icing on the cake!
Print | posted on Friday, 15 October 2010 12:56 PM