AutoMockingContainer and ASP.NET MVC: Round 1
I resolved to pace myself a little better in '08 on this blog. But then, I also resolved not to keep any of my resolutions. Mostly because I like the circular reference.
I'm delving a little more deeply into the ASP.NET MVC framework these days in preparation for a couple of upcoming presentations. And I've really liked using Jacob Llewallen's AutoMockingContainer in other projects so naturally, I wanted to take that into MVC and use it to create my controllers:
controller = container.Create<SongControllerTester>( mocks );
(NOTE: I'm using the Test Specific Subclasses espoused in Phil Haack's post on the subject but it doesn't matter if you use the subclasses or the actual base controllers.)
This fails with the error: MissingMethodException: Can't find a constructor with matching arguments.
Luckily, the AutoMockingContainer's source is available. Even more luckily, so is Windsor's. So after some digging, here is what appears to be happening:
When the AutoMockingContainer attempts to create SongControllerTester class, it adds the class's type to its own internal Windsor container. It then attempts to resolve that type, thus retrieving an instance of the object from the container.
During that retrieval process, Windsor loops through the object's properties and tries to resolve the ones that it can (for the properties that are objects). Typically, they can't be resolved unless they've also been added to the container. But the cool thing about the AutoMockingContainer is that it wires itself into this process and will create dynamic mocks for the objects that represent these properties. However, these objects must have a default constructor.
The MVC Controller object has a ControllerContext property and the ControllerContext object does not have a default constructor. Hence, no dynamic mock for it.
And unfortunately, I haven't found a way around this yet. Marking ControllerContext as non-dynamic, stubbed, or non-mocked won't work, nor am I able to get the AutoMockingContainer to create an instance of ControllerContext (there is no setter on its Controller property).
So in lieu of the amount of time I've already spent looking into this, I'll have to switch to more traditional methods of creating my controllers and mocking their dependencies.
Kyle the Mockable