Search code examples
asp.net-mvcasp.net-mvc-3ninjectmspec

How can I use Ninject in my ASP MVC MSpec tests?


I'm trying to write an MSpec test that instantiates one of my controllers with all the correct Ninject bindings. How do I go about doing that? This is what I have so far:

    [Subject(Concern.Initialization)]
public class when_permanent_employee_page_is_loaded_for_first_time
{
    private static PermanentEmployeeController controller;

    Establish context = () =>
        {
            NinjectControllerFactory controllerFactory = new NinjectControllerFactory();
            ControllerBuilder.Current.SetControllerFactory(controllerFactory);
            controller = (PermanentEmployeeController)controllerFactory.CreateController(new RequestContext(), "PermanentEmployee");
        };

    private Because of = () => controller.Index();

    private It should_load_all_available_jobs = () =>
        { 
            var blah = controller;
            var blah3 = 3;
        };
    It should_load_all_available_locations;
    It should_load_all_available_departments;
}

In the above code I'm simply trying to see if I can instantiate my controller with all the Ninject bindings in tact. The NinjectControllerFactory class looks like this:

public class NinjectControllerFactory : DefaultControllerFactory
{
    private IKernel kernel = new StandardKernel(new DefaultModule());

    public IKernel Kernel 
    { 
        get
        {
            return kernel;
        }
        set
        {
            this.kernel = value;
        }
    }

    protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
    {
        if (controllerType == null)
        {
            return null;
        }

        return (IController)kernel.Get(controllerType);
    }
}

And the DefaultModule class like this:

public class DefaultModule : NinjectModule
{
    /// <summary>
    /// Performs the binding of interfaces to their respective implementations. 'Tis very cool.
    /// </summary>
    public override void Load()
    {
        // Data service bindings
        Bind<IJobService>().To<JobServiceImpl>().InTransientScope();
        Bind<IJobWsWrapper>().To<JobWsWrapperImpl>().InTransientScope();

        // View model factory bindings
        Bind<IPermanentEmployeeViewModelFactory>().To<PermanentEmployeeViewModelFactoryImpl>().InTransientScope();
    }
}

So my question is: is there a way to specify the bindings of my Ninject module in my MSpec test and then have my instantiated controller use those bindings? I want to avoid instantiating my Controller like this: var controller = new Controller() since that doesn't allow me to test the Ninject bindings. I've also looked into the TestControllerBuilder class from the MvcContrib library but I haven't figured out how to instantiate controllers with Ninject bindings with it. Thanks for the help!


Solution

  • Ok I figured out how to initialize my controller along with the Ninject Bindings in my MSpec tests! Well I didn't figure it out. A coworker did but that's irrelevant now. Here is how it's done:

        public class when_permanent_employee_page_is_loaded_for_first_time
    {
        private static Mock<IJobService> jobServiceMock;
        private static Mock<IUtilsService> utilsServiceMock;
        private static PermanentEmployeeController controller;
        private static ContextMocks mocks;
    
        private static IList<Job> jobs = new List<Job>();
        private static IList<string> departments = new List<string>();
        private static IList<string> locations = new List<string>();
        private static PermanentEmployeeJobsViewModel viewModel;
    
        Establish context = () =>
            {    
                jobServiceMock = new Mock<IJobService>();
                jobServiceMock.Setup(x => x.GetJobs(1)).Returns(jobs);
                jobServiceMock.Setup(x => x.GetDepartmentsFromJobs(jobs)).Returns(departments);
                jobServiceMock.Setup(x => x.GetLocationsFromJobs(jobs)).Returns(locations);
    
                utilsServiceMock = new Mock<IUtilsService>();
    
                var kernel = new StandardKernel(new DefaultModule());
                kernel.Rebind<IJobService>().ToConstant(jobServiceMock.Object);
                kernel.Rebind<IUtilsService>().ToConstant(utilsServiceMock.Object);
    
                controller = kernel.Get<PermanentEmployeeController>();
                mocks = new ContextMocks(controller);
            };
    
        Because of = () =>
            {
                PartialViewResult view = (PartialViewResult)controller.Index();
                viewModel = (PermanentEmployeeJobsViewModel)view.ViewData.Model;
            };
    
        It should_load_all_available_jobs = () =>
            {
                jobServiceMock.Verify(x => x.GetJobs(1)); 
                jobServiceMock.Verify(x => x.GetDepartmentsFromJobs(jobs));
                jobServiceMock.Verify(x => x.GetLocationsFromJobs(jobs));
                viewModel.Departments.ShouldEqual(departments);
            };
    
        It should_load_all_available_locations;
        It should_load_all_available_departments;
    }
    

    Ok that's it :). Hopefully someone else can benefit from this answer. Special thanks to my coworker for figuring this out. You know who you are :D