Crikey, am I having a time testing RedirectToAction on my controller with the new MVC Preview! How much of it is me and how much is the beta-ness of the framework, I will leave to your fair and impartial judgement.
I upgraded relatively easily from the December CTP. Here's a quick summary of what was involved:
I think that was about it. After that, the bad boy compiled and all the tests passed and it was on to my next challenge. Namely, drop the test-specific subclasses in favour of the extension methods mentioned by Haackselman in post and video form.
It went pretty smoothly at first. I added the MvcMockHelpers class, incorporated a FakeViewEngine, and went about my merry way converting asserts that used testController.RenderedView to ones using fakeViewEngine.ViewContext.ViewName. Ditto for RenderedViewData to ViewData.
Then came the last test. The one that checked to see if the action correctly called RedirectToAction. There is no property in the ViewContext to check to see which view was the eventual target. And after checking out the only post I could find on the subject (which has a lot more information on it today than it did two days ago when I went through this problem), I got an error in the test that turned out to be misleading:
System.NullReferenceException: Object reference not set to an instance of an object.
at Trilogy.Gunton.Web.MyRoute.GetRouteData(HttpContextBase httpContext) in MyRoute.cs: line 117
at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase context)
at Trilogy.Gunton.Tests.Unit.Controllers.JobControllerFixture.Save_action_should_send_job_to_service() in JobControllerFixture.cs: line 150
The MyRoute class is courtesy of Reflector and I used it to determine the problem. It was two days ago and I don't have the memory I used to but I'm pretty sure it was something deep within the bowels of the Route class. It's calling GetRouteData on the class to determine which URL to redirect to and that method has a call:
IList source = SplitUrl(httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo);
And the AppRelativeCurrentHolyCowThisIsALongName and PathInfo properties have not been mocked. I think it has something to do with the fact that the controller's fake ControllerContext is created with an empty RouteData. Not sure how the RouteTable created in Global.asax.cs eventually translates into the RouteData (assuming it does) because by that time, I had enough fodder for this post (which is the only reason I took it as far as I did).
Again, this is speculation but the net result is, RedirectToAction remains untestable by me. I've heard tell that there is a way but as it stands now, I've put some comments into my tests to remind me to revisit them once a better way exists.
But if you're the type that's more anal about code coverage than best practices, using Response.Redirect instead of RedirectToAction works like a charm.
Kyle the Undirected