windsor mvc controller factory

This is the third in a series of posts illustrating building a custom Windsor registration process. Here I want to illustrate test driven development on another Windsor implementation that will fit into the upcoming registration process - a Windsor Controller Factory for ASP.NET MVC.

I start, as always, with my context specification class:
(If unfamiliar with this library, my context specifications series my be of interest)

[Observations] 
public class when_a_known_controller_is_requested_from_the_windsor_controller_factory : 
  observations_for_a_sut_with_a_contract<IControllerFactory, WindsorControllerFactory>  
{ 
    private static Type controllerType;
    private static IController returnedController; 

    private context c = () => controllerType = typeof (FakeController);

    private because b = () => returnedController = sut.CreateController(null,
                                                                     controllerType.Name); 

    [Observation] 
    public void should_return_an_instance_of_the_controller() 
    { 
        returnedController.should_not_be_null(); 
    } 
 }

Here, in my because "Act" delegate I'm requesting a controller via the IControllerFactory interface method CreateController and asserting that it returns something.
The implementation to make this build is as follows:

public class WindsorControllerFactory : IControllerFactory
{
    private IWindsorContainer container;

    public WindsorControllerFactory(IWindsorContainer container)
    {
        this.container = container;
    }

    public IController CreateController(RequestContext requestContext, string controllerName)
    {
        return null;
    }

    public void ReleaseController(IController controller)
    {
        throw new NotImplementedException();
    }
}

Running the tests it predictably fails, so in true TDD style I add the most basic implementation to make the test pass:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    return new FakeController2();
}

I now improve upon this with a second observation:

[Observation]
public void should_return_the_correct_controller()
{
    returnedController.should_be_an_instance_of<FakeController>();
}

This test fails and I implement enough to pass the test:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    return new FakeController();
}

Moving onto a new specification, I want to ensure it now asks for the controller instance from the Windsor Container instead of providing its own instance as it currently does:

[Observations]
public class when_a_controller_is_requested_from_the_windsor_controller_factory :
  observations_for_a_sut_with_a_contract<IControllerFactory, WindsorControllerFactory>
{
    private static IWindsorContainer container;
    private static string controllerName;

    private context c = () =>
                            {
                                container = the_dependency<IWindsorContainer>();
                                controllerName = "acontroller";
                            };

    private because b = () => sut.CreateController(null, controllerName);

    [Observation]
    public void should_ask_the_container_to_resolve_the_controller()
    {
        container.was_told_to(c => c.Resolve<IController>(controllerName));
    }
}

To make this test pass, I implement the following:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    container.Resolve<IController>(controllerName);
    return new FakeController();
}

A second observation in this specification will now ensure it uses the correct instance when returning:

[Observations]
public class when_a_controller_is_requested_from_the_windsor_controller_factory :
  observations_for_a_sut_with_a_contract<IControllerFactory, WindsorControllerFactory>
{
    private static IWindsorContainer container;
    private static string controllerName;
    private static IController returnedController;
    private static IController theExpectedController;

    private context c = () =>
                            {
                                container = the_dependency<IWindsorContainer>();
                                controllerName = "acontroller";
                                theExpectedController = an<IController>();

                                container.expect_at_least_once(w => 
                                              w.Resolve<IController>(controllerName))
                                         .IgnoreArguments()
                                         .Return(theExpectedController);
                            };

    private because b = () => returnedController = sut.CreateController(null, controllerName);

    [Observation]
    public void should_ask_the_container_to_resolve_the_controller()
    {
        container.was_told_to(c => c.Resolve<IController>(controllerName));
    }

    [Observation]
    public void should_return_the_controller_obtained_from_the_container()
    {
        returnedController.should_be_equal_to(theExpectedController);
    }
}

Now I am setting up an expectation on my mock of IWindsorContainer and returning a mock controller instance. I then assert that this is the correct one coming back from the method call. This fails, so the implementation then becomes:

public IController CreateController(RequestContext requestContext, string controllerName)
{
    return container.Resolve<IController>(controllerName);
}

This specification now passes, but it breaks the original set of observations as we no longer have the FakeController hard coded and it is not registered in those specifications.

I'll cover revising this in my next post.



0 comments: