I have found that my controller tests usually contain some repetitive code for checking the ActionResult type, for example doing a safe typecast to ViewResult and asserting a notnull, checking the viewName, ViewData.Model type, etc. Some extension methods for the ActionResult and the ViewResult classes can take care of this.

Example:
[Fact]
public void Calling_ViewHistory_Should_ShowHistoryList()
{
    indexRepos.Expect(x => x.GetChangesets("SvnRepos", "/trunk", 5, 10))
        .Return(testData.SvnChangesets);

    var model = controller.ViewHistory("SvnRepos", "trunk", 5)
        .ReturnsViewResult()
        .ForView("History")
        .WithViewModel<HistoryViewModel>();            
               
    Assert.NotEmpty(model.Changesets);
    
    indexRepos.VerifyAllExpectations();
}

ReturnsViewResult asserts that the returned ActionResult is actually a ViewResult, ForView asserts that the ViewResult has the correct viewName set, WithViewModel asserts that the ViewData.Model has the specified type and returns the model.

Here is the code for the extension methods:
public static ViewResult ReturnsViewResult(this ActionResult result)
{
    ViewResult result = result as ViewResult;
    Assert.NotNull(result);
    return result;
}

public static ViewResult ForView(this ViewResult result, string viewName)
{
    Assert.Equal(viewName, result.ViewName);
    return result;
}

public static ViewResult ForMaster(this ViewResult result, string masterName)
{
    Assert.Equal(masterName, result.MasterName);
    return result;
}

public static ContentResult ReturnsContentResult(this ActionResult result)
{
    var contentResult = result as ContentResult;
    Assert.NotNull(contentResult);
    return contentResult;
}

public static TViewModel WithViewModel<TViewModel>(this ViewResult result) where TViewModel : class
{
    TViewModel viewData = result.ViewData.Model as TViewModel;
    Assert.NotNull(viewData);
    return viewData;
}

public static TType WithViewData<TType>(this ViewResult result, string key) where TType : class
{
    TType viewData = result.ViewData[key] as TType;
    Assert.NotNull(viewData);
    return viewData;
}
The idea for this is taken from browsing the source of the Suteki Shop, a very nicely coded ASP.NET MVC app. I only changed some of the method names. I also found a very simple but nice little extension method to the string class:
public static string With(this string format, params object[] args)
{
    return string.Format(format, args);
}

//...

string msg = "First name: {0}, Last name {1}".With(user.FirstName, user.LastName);

Simple, nice and elegant :)

On a completely unrelated topic, Olson Jeffery has gotten together a the first release of Boo Lang Studio, it still a pretty ruff alpha version, if you try it please raise your issues in the codeplex issue tracker!

6 comments:

Anders said...

Nice!

Paolo Izmoto said...

Hi,

Super Cool :)
I had a situation just like ur observation. The extension methods for Unit Testing helped me in a great way.

Nick said...

Good stuff, thanks Torkel!

Kimoz said...

Nice stuff. Did an MSTest version with some additonal extensions. Thanks :)

Kimoz said...

Cool :) Inspired me to do an MSTest versjon with som added extensions and generics.

Thanusha said...

Cool.wonderful explanation on Action Result method unit testing.

ASP.Net MVC Training
Online MVC Training
Online MVC Training from India
MVC Training in Chennai
.Net Training in Chennai