Search code examples
asp.net-mvcunit-testinglinq-to-sqltestability

How to abstract Linq2SQL for testability


I'm working on a project that uses Linq2SQL for data access. The project is made up of an ASP.NET MVC application and 8 class libraries. Most of the class libraries have their own L2S data classes.

As part of the work I'm doing, I'm trying to get the various components under test to introduce some stability clean up the codebase, it currently makes heavy use of static classes and methods, and the controllers have static DataContexts which are used throughout.

How can I refactor the L2S usage so that I can test the controller actions?

I've introduced dependency injection into the app to decouple some of the other services but I don't want the DataContext as a dependency property of the controllers because I want to control the instantiation of the DataContexts and their DataLoadOptions.

One thing I did try was taking advantage of the partial classes that L2S generates and added an Interface to the DataContexts, but I found that the abstraction bubbled it's way up into the application rather than staying down in the class libraries. It didn't feel like the right way of doing things and that it would be a pain to maintain. Has anyone had any particular success or failure with this method?


Solution

  • I use Repository pattern to hide DataContext inside. Repositories are abstractions, so suite really nice with Dependency Injection principle.

    For instance, you define some repository.

    public interface IUserRepository
    {
        User Get(int id);
        User Save(User user);
        void Delete(User user);
    }
    

    The implementation is something like

    public class UserRepository : IUserRepository
    {
        private MyDataContext _context;
    
        UserRepository() 
        {
            _context = new MyDataContext();
        }
    
       // ...
    
    }
    

    Now, controller depends only on interface.

    public UserController : Controller
    {
        UserController(IUserRepository userRepository) { }
    }
    

    So, it's perfectly testable since you can mock IUserRepository in your tests.