Linq2SQL and Repository Pattern: Unit Testing
In previous part we saw how to implement a Repository pattern over Linq2SQL. Let’s see in more detail how we can test this. If you are not new to unit testing and mocking, feel free to skip.
Suppose we have a controller that is using a IRepository<Product>
and we need to have two in-memory products returned when querying. Basically, the controller itself looks like this:
1 | public class HomeController : Controller |
and the test would be:
1 | public class HomeControllerTests |
So how do we create a IRepository<Product>
? Do we mock it using the interface? Do we create the implementation that accepts our in-memory collection? The first thing that’d come to mind is to create a mock object using the interface:
1 | productRep.Expect(r => r.FindMany(Arg<Func<Product, bool>>.Is.Anything)).Return(products); |
There are some things that I’m not happy with. The arguments are over-specified and if you try to create a more specific one for FindMany method, it would result a somewhat unreadable code. But as far as running and passing the test goes, it is okay and runs fine. The second way to go is to create another constructor on Repository<T>
that accepts IEnumerable<T>
for the in-memory data. We’ll use this overload just in tests.
1 | public class Repository<T> : IRepository<T> where T : class |
This way too has its downsides. It is a little intrusive (having an API that should be called in tests only) but will lead to a more readable test. In the test, instead of mocking the interface we can now create the implementation and pass in the collection. There’s no need to setup a mock object:
1 | var productRepo = new Repository<Product>(new DataContextStub(), products); |
Testing the CRUD operations is pretty straight forward. Let’s say the controller has an action that creates a customer.
1 | public ActionResult CreateCustomer() |
There are two things to test here. First checking the correct customer is being saved, the second part is to make sure Save operation is called. We could also check the message being displayed but let’s skip it for brevity reasons.
1 | [ ] |
If you need to test the Repository<T>
implementation it’d be next to impossible using .NET FX 3.5. Why? Because the Table<T>
class is sealed and you can not mock sealed classes (not with conventional tools that is, but you can given the right tool for the job). The solution? the easiest one would be to upgrade to .NET 4.0. Doing so, there is a ITable<T>
interface which you can use to mock out the tables in the data context. You may download the whole source code from here.