The authors are also authors of ASP.NET MVC 2 in Action
While the MVC Framework gives you a lot of control for using the framework and creating controllers, there are still some features of ASP.NET that are difficult to simulate in a test. By taking that difficult-to-test code out of an action and putting it into the Execute method of an action result, the actions become significantly easier to unit test. The reason for this is that when you unit-test an action, you assert the type of the action result that the action returns and the state of the action result. The execute method of the action result is not executed as part of the unit test.
Listing 1 shows how moving the FormsAuthentication.SignOut() call from an action and into the action result abstracts that line of code and prevents it from executing from within the action method.
public class LogoutActionResult : ActionResult { public RedirectToRouteResult ActionAfterLogout { get; set; } <b>A </b> public LogoutActionResult(RedirectToRouteResult actionAfterLogout) <b> B </b> { ActionAfterLogout = actionAfterLogout <b>B </b> } public override void ExecuteResult(ControllerContext context) FormsAuthentication.SignOut(); <b>C </b> ActionAfterLogout.ExecuteResult(context); <b>D </b> } } <b> A RedirectToRouteResult is testable<br> B Constructor sets ActionAfterLogout<br> C SignOut is hard to test <br> D ActionAfterLogout result is executed. </b>
This allows an action to return a LogoutActionResult. The testing of that method does not have to deal with calls to the FormsAuthentication class. The test can just assert that the LogoutActionResult was returned from the action. The test can also assert the values in the RedirectToRouteResult to make sure that the action correctly setup the redirect.
Listing 2 shows that the Logout action method returns the new LogoutActionResult method.
public ActionResult Logout() { return new LogoutActionResult(RedirectToAction("Index","Home")); A } <b>A The testable Logout action method </b>
The constructor parameter to the LogoutActionResult is a RedirectToAction result that will redirect the browser to the Index action on the HomeController.
Summary
The advanced controller extensibility in MVC 2 allows you to tweak the framework easily. The IController interface allows the most control, but the various controller base classes provide some very useful but flexible capabilities. Actions help you easily break down basic functions of a single controller. Action filters provide hooks for inserting code before or after action execution. Action selectors help you provide hints to the action invoker about which action should be selected for execution, and action results help to encapsulate repetitive rendering logic.