Search code examples
asp.net-mvcasp.net-mvc-4tddunity-containermoq

MVC4 TDD with multiple layers


I am learning about DI, IoC and MOQ so I can TDD my new MVC4 application.

I followed a lot of examples online but there is one thing I cannot get my hands around.

My application consists out of 3 layers (physical projects):

  1. Application layer (controllers / models / standard MVC4 stuff).
  2. Business layer (does all the calculating and processing data).
  3. DAL (EF5).

Now I have a very simple UserController

public class UserController : Controller
{
    readonly IUserRepository _repository;

    public UserController(IUserRepository rep)
    {
        _repository = rep;
    }

    public ActionResult Index()
    {
        IList<User> users = _repository.Get(10);
        return View(users);
    }

Dependency is injected with Unity and this works fine.

In the business layer I have the repositories:

public interface IUserRepository
{
    IList<User> Get(Int32 count);
}

public class UserRepository : IUserRepository
{
    public IList<User> Get(Int32 count)
    {
        // Here I fetch the data from the Database
        // and do some stuff with it, this can be
        // quite a big method.
    }
}

Now I need to access my DAL which I can do in my UserRepository's Get method.

Only how do I unit test this? There should not be a dependency in the class I think because of the testability.

If I use the actual UserRepository class in my unit test to test it will go to the DAL and use data from there, but I need mock data.

Do I need to make another IUserDataRepository where the actual data is fetched from the database and pass this into the UserRepository constructor or should I use Unity to handle this for me?

Possible answer?

I created a new interface called Users:

public class Users: IUsers
{
    private readonly IUserRepository _userRepository;
    public Users(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public User Get(String id)
    {
       // Do all the magic here here
    }
}

From this interface IUsers:

public interface IUsers
{
    User Get(String id);
}

But I moved my database oriented repositories to the DAL:

public class UserRepository : IUserRepository
{ 
    public User Get(String id)
    {
        // Retrieve the user from the database with EF5
    }
}

public interface IUserRepository
{
    User Get(String id);
}

The controller stayed about the same, but now has a dependency to the IUser interface:

public class UserController : Controller
{
    readonly IUsers _users;

    public UserController(IUsers users)
    {
        _users = users;
    }

    public ActionResult Index()
    {
        User user = _users.Get(10);
        return View(users);
    }
}

Solution

  • Repositories are the gateway to the database. They contain the smallest amount of code as possible (no business stuff) and just do what it takes to get the data out of the database (or save it into the database).

    Since it is directly coupled to your database, you can't unit test it. You could only unit test it when you abstract that logic away, but that is exactly what repositories are for, so that is a useless abstraction.

    Instead, write integration tests for them that set up a database transaction and call the real repository and rollback that transaction when done.