This is howMVC controller actions should be unit tested
Note the explicit dependencies on IAttendeeRepository and IViewEngine. That means that I'll be interacting with those two dependencies in this controller. Here is my unit test (this passes, by the way):
This is a pretty straightforward unit test except for the line before calling the Register() method. I have to use setter-injection to set a stubbed ControllerContext. If I don't, the Register() method will bomb with an exception when the ViewContext is created, and the code tries to get an HttpContextBase off of the ControllerContext. It'll throw a NullReferenceException. My code doesn't really care about the ControllerContext or what is in it, but because of how the code is structured, I must use setter injection to break this dependency. Note that testability is next up on the list of things to do for the MVC Framework team.
Preview2 (March CTP) was all about getting the routing engine out into its own assembly so that it can be used separate from MVC controllers. Also, the MVC Framework is "binnable". You can xcopy deploy it. There is plenty of time to fix these things, and the team is working on it. You can also be sure that I'll keep raising the issue because I've been test-driving code for three years, and it's instinct now to see what is easy and frictionless and separate it from code that is harder to test than it should be. Overall, pretty good for a CTP.
The following is what I would like to write. The following is how I would like my test to look. Notice just the absence of the ControllerContext line.
Note that my unit test is concerned with explicit dependencies and doesn't know or care that I'm making use of a PROTECTED method named "RenderView" inside my action. That detail doesn't matter because the interaction with the IViewEngine is what is important.
I also understand that I could use the Legacy code pattern of "Extract and Override Call" (Feathers, p348). Microsoft has already provided the extracted method, RenderView. I can override the call to break the dependency, but that pattern is meant to be used as a dependency-breaking technique with legacy code. If you haven't read Michael Feathers' book, Working Effectively with Legacy Code, you should order it right now. It talks about all kinds of dependency-breaking techniques in order to write unit tests on existing code. My goal in providing feedback to the MVC Framework team (and I provide feedback, believe me) is to have this framework be something that I would want to use. There is plenty of time to make the necessary changes, and the team is working hard.
I revised this post a bit after chatting on the phone with Scott Guthrie this evening. We'll see some testability improvements in the next drop, and the team is aiming to make drops around every 6 weeks or so.
Note: I'm playing around with using "var" for locals. Not sure if I like it yet. We'll see. No need to comment on the "vars". Comment on controllers, actions, and unit tests.