Welcome to William's ekasi

[ Log On ]
Testing for RedirectToAction results
2010/01/01
Tags:

What a pain!

If a controller’s action method returns RedirectToView(“NewView”) the result is a RedirectToRouteResult.  This is good.

Unless the routing engine is actually in play (which it isn’t while we’re unit testing) the actual NewView action method won’t be called.  Which is kind of good because it forces you to test one action method at a time.  But what if your action method returns multiple RedirectToRouteResults?

public ActionResult Index()
{
    var viewModel = GetViewModel();
    
    if (SomethingNotRight(viewModel))
    {
        // redirect to error page
        return RedirectToAction("Error");
    }
    else if (SomethingDifferent(viewModel))
    {
        // redirect to details page
        return RedirectToAction("Details");
    }

    return View("Index", viewModel);
}

At first glance our test would look something like this:

[TestMethod]
public void Index_WithZeroItems_ReturnsErrorView()
{
    // Arrange
    ItemIndexViewModel mockViewModel = MockRepository.GenerateMock();
    mockViewModel.Expect(m => m.GetItems()).Return(new List()).Repeat.Any(); // should redirect to Error

    var controller = new ItemsController();
    controller.ItemIndexViewModel = mockViewModel;

    // Act
    var result = controller.Index();

    // Assert
    Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
    }

So we have asserted that A RedirectToRouteResult has been returned, but which one?

The RedirectToRouteResult exposes a RouteName property and RouteValues property.

What it DOES give us though, is the RouteValues property is a dictionary populated with the name of the action we redirected to.  So to check which action we’re redirecting to we simply have to check the name of the action within the dictionary.  So our test method becomes:

public void Index_WithZeroItems_ReturnsErrorView()
{
    // Arrange
    ItemIndexViewModel mockViewModel = MockRepository.GenerateMock();
    mockViewModel.Expect(m => m.GetItems()).Return(new List()).Repeat.Any(); // should redirect to Error

    var controller = new ItemsController();
    controller.ItemIndexViewModel = mockViewModel;

    // Act
    var result = controller.Index();

    // Assert
    Assert.IsInstanceOfType(result, typeof(RedirectToRouteResult));
    Assert.AreEqual("Error", (result as RedirectToRouteResult).RouteValues["action"]);
}

So we tested that the CORRECT RedirectToRouteResult is returned, just as expected.

Add Comment

No comments have been posted yet