Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to solve base Controller dependency injection for testing purposes?

I have implemented my mvc base controller called DefaultController using dependency injection pattern in order to be able to construct test cases. Example below:

public class DefaultController : Controller
{
    protected readonly ISessionHelper _sessionHelper;
    string _thisUserOpenID;
    protected IUsersRepository _UserRepository;
 ... 
    public DefaultController()
    { } //not for testing

    public DefaultController(ISessionHelper session, IUserRepository repo)
    {
       _sessionHelper=session;
       _UserRepository = repo;
     }
 }

Then I have my controllers using this controller, homecontroller, usercontroller, etc.

Now, building some test cases I found myself in a situation where I don't know how to actually use the injection dependency pattern.

    [TestMethod]
    public void Welcome_Message_In_ViewData_Has_Coockie_User_Display_Name()
    {
        // Below I want to insert FakeRepositories using 
        //ISessionHelper and so on. but the constructor 
        //for homecontroller don't have it.
        HomeController controller = new HomeController(); 

Any ideas?

like image 223
Geo Avatar asked Sep 17 '09 23:09

Geo


2 Answers

Your HomeController needs to have a matching "injectable" constructor, which would then call the base constructor.

public HomeController(ISessionHelper session, IUserRepository repo)
  : base(session, repo)
    {

    }

Now, in your test, you would create your HomeController using that constructor, and pass in a mocked up session and user repository. Speaking of mocking, you might also be interested in Scott Hanselman's MvcMockHelpers classes, with code for many popular mocking frameworks.

like image 94
womp Avatar answered Sep 28 '22 18:09

womp


I don't see why you have two constructors. You should only have one, get rid of the constructor with no parameters. Using a DI framework like Castle Windsor, or my preferred one, Autofac will handle all of this for you. Then as far as testing is concerned use something like Moq. Ie

public DefaultController(ISessionHelper session, IUserRepository repo)
{
   _sessionHelper = session;
   _UserRepository = repo;
}

Register DefaultController, ISessionHelper and IUserRepository with your DI framework. Something along the lines of:

Register(new DefaultController()); (it is something like that in Autofac)
Register<SessionHelper>().As<ISessionHelper>();
Register<UserRepository>().As<IUserRepository>();

That way, you can pull DefaultController from the container and the DI framework will inject the two parameters for you. I wrap up a static method to access my DI container, it looks like:

var controller = IoC.Resolve<DefaultController>();

Basically head over to Autofac and have a look. There's also a web module for registering your Controllers for you.

Then for testing just use Moq, or find some form of "AutoMocker" (google it). I would do:

var session = new Mock<ISessionHelper>();
var repo = new Mock<IUserRepository>();
repo.Setup(s => s.FindById(123)).Returns(new User());

var conroller = new DefaultController(session.Object, repo.Object);
controller.Execute();

Also ewww repositories. With .Net and generics etc... just create yourself an nice ISession.

var session = IoC.Resolve<ISession>();
var user1 = session.Get<User>(123);
var user2 = session.Get<User>(u => u.Username == "admin");
session.Update(user3);

Means you only need to pass in one thing and you can use it for whatever. Rather than having to pass in sometimes many repositories. Also sets you up nicely for the Unit Of Work pattern.

like image 25
Bealer Avatar answered Sep 28 '22 17:09

Bealer