0

I'm using LINQ-to-SQL with ASP.NET MVC 4, and as of this moment I have a repository layer which contacts a real database. This is not very good when I want to unit test.

Also there should never be a logic in the repository layer, so this is why I want to mock the LINQ DataContext so I can create a service layer that talks either to the mock DataContext or to the real DataContext.

I see that my LINQ DataContext class inherits DataContext, but there is no interface, so I can't really mock that. I also see that DataContext uses Table<> class and there exists an interface ITable, so I probably could mock that. Also my LINQ DataContext is a partial class, so maybe I could manipulate that in some kind of way?

When I google this, all articles are from 2008 and are outdated. Can anyone guide me in the right appropriate direction?

Here is an example of what I want to do. I will have seperate service class for each controller.

public class MyServiceClass
{
    IDataContext _context;

    // Constructors with dependency injection

    public MyServiceClass()
    {
        _context = new MyRealDataContext();
    }

    public MyServiceClass(IDataContext ctx)
    {
        _context = ctx;
    }

    // Service functions

    public IEnumerable<ModelClass> GetAll()
    {
        return _context.ModelClass;
    }

    public ModelClass GetOne(int id)
    {
        return _context.Where(s => s.ID == id).SingleOrDefault();
    }
}

1 Answer 1

1

Although Linq-to-Sql is still supported in .NET 4+, it has been pushed back in favor of Entity Framework. That's probably why you're finding mostly older articles.

Anyway the best way to go is to write your own DataAccess layer-interface, used through your application. You then can have an implementation of that interface that uses your linq-to-sql for production and a mocked implementation for your unit tests.

Use dependency injection to instantiate the actual implementation class.

For creating a mock implementation you do it either manually (Creating a class in your test project that implements the IDataContext interface but returns hard-coded data) or use one of the mocking frameworks around there.

I have not used every one of them but moq was quite nice. Microsoft has now also their framework in Visual Studio 2012 called Fakes, worth looking at.

Example of using moq

var expectedResultList = new List<ModelClass>(){ ... };
var mockDataContext = new Mock<IDataContext>();
mock.Setup(c => c.GetAll()).Returns(expectedResultList);

MyServiceClass service = new MyServiceClass(mockDataContext.Object);
var list = service.GetAll();
Assert.AreEqual(expectedResultList, list);

In this code you set up your mock object so that it will return your expected list when the GetAll method is called. This way you can easily test your business logic based on different returns from your data access.

Example of IDataContext

public interface IDataContext<T>
{
   IEnumerable<T> GetAll();
   T GetById(int id);
   int Save(T model);
}

public class LinqToSqlDataContext<T> : IDataContext<T>
{
    private DataContext context = new DataContext();

    public IEnumerable<T> GetAll()
    {
         // query datacontext and return enumerable
    } 

    public T GetById(int id)
    {
         // query datacontext and return object
    }

    public int Save(T model)
    {
        // save object in datacontext
    }
}

public class MyFirstServiceClass
{
     private IDataContext<MyClass> context;
     public MyFirstServiceClass(IDataContext<MyClass> ctx)
     {
        this.context = ctx;
     }
     ....
}
public class MySecondServiceClass
{
     private IDataContext<MySecondClass> context;
     public MyFirstServiceClass(IDataContext<MySecondClass> ctx)
     {
        this.context = ctx;
     }
     ....
}
11
  • This is a large project I'm taking over and it's not optional to switch to EF. But in regard to LINQ, do you have an example for me?
    – Gaui
    Commented Jun 5, 2013 at 9:22
  • Well, it's pretty much what you already have in your code. Your service class will work against your IDataContext interface. In production you will use an IDataContext implementation against your liq-to-sql, in Unit tests you can use a mocked implementation.
    – Ronald
    Commented Jun 5, 2013 at 9:43
  • Just make sure your IDataContext does NOT expose any linq-to-sql specific classes
    – Ronald
    Commented Jun 5, 2013 at 9:43
  • Yes, but I'm not sure HOW to mock the DataContext. If you could help me in the right direction, I would really appreciate it.
    – Gaui
    Commented Jun 5, 2013 at 10:19
  • 1
    Yes, you're in the right direction. Usually you may find this in implementations of a Unit Of Work, where the unit allows you to access multiple repositories and then commit/rollback all changes done. there are many examples on the web of how to implement this, most focused on Entity Framework but easily to be changed to Linq-to-Sql.
    – Ronald
    Commented Jun 5, 2013 at 13:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.