In one of our projects, we are using Linq to Sql to work with database. It is really nice to use, because it allows you to query a database using Linq.
Everything is fine, until you want to unit test your code… How to mock DataContext? Not so easy. DataContext does not implement any interface, Table is sealed. What to do?
I have been searching for a solution for a while, there are many different approaches. I’ll show what I have found the most useful and is quite simple to implement.
The solution is, as always, to create an abstraction. So, I created an interface for abstracting the DataContext and implemented it in a DataContext partial. The interface defines methods to query the database and save our modifications (insert, update, delete). Table class is sealed, so I can’t mock it and I can’t also expose it in the interface. For me, for querying, the best way is to expose DataContext’s tables by IQueryable. It allows me to use Linq and also gives possibility to do lazy/eager loading. For saving modifications – four methods: InsertOnSubmit(), UpdateOnSubmit(), DeleteOnSubmit() and of course SubmitChanges(). So, here is the interface.
public interface IDataContext { public T Table<T>(); public void InsertOnSubmit(T entity); public void UpdateOnSubmit(T entity, T originalEntity); public void DeleteOnSubmit(T entity); public void SubmitChanges(); }
You can use it almost the same as you were using DataContext directly.
var customer = context.Table<Customer>() .Where(x => x.Name == "customer1") .Single(); customer.Name = "newCustomerName"; context.SubmitChanges();
The implementation in DataContext partial class is following.
public partial class MyDataContext : IDataContext { public T Table<T>() { return GetTable<T>(); } public void InsertOnSubmit<T>(T entity) where T : class { if (null != entity) this.GetTable<T>().InsertOnSubmit(entity); } public void UpdateOnSubmit<T>(T entity, T originalEntity) where T : class { if (null != entity) this.GetTable<T>().Attach(entity, originalEntity); } public void DeleteOnSubmit<T>(T entity) where T : class { if (null != entity) this.GetTable<T>().DeleteOnSubmit(entity); } }
This is fairly easy and short implemention, isn’t it? Now, you can mock your database without any problems. Example using Moq library:
var customerList = new List<Customer>(); //populate customer list var context = new Mock<IDataContext>(); context .Setup(x => x.Table<Customer>()) .Returns(customerList.AsQueryable());
We return a list by our mock, Linq to Objects do the rest. There is of course a risk, that Linq provider for Linq to Sql can behave differently than provider for Linq to Objects, but in my tests it works very well.
If your code (you want to test) is using many tables, the setup of test may be quite long (lines of code). For such situation, better option is to write a generic mock context acting like an in-memory database. I have done it also, I will show it in another post.
So, that’s all. Enjoy!