Unit Testing ASP.NET MVC Controller Action contains specific ActionFilter Attributes

ActionFilters in ASP.NET MVC are great.

You can now easily share logic between controllers without having to inherit from a base controller, that does the common work.

I have a content heavy application that supports a set of layouts. Each layout is rendered by setting the Layout view dynamically, which I do from an ActionFilter. My ActionFilter is fully tested, but when you delegate work to an ActionFilter, you should write a test that ensures the filter is defined on the action.

Not surprisingly, this is very simple and relies on reflection (Download from Gist: https://gist.github.com/2605628):

/// <summary>
/// Verifies the controller action, contains an attribute of the specified attributeType.
/// </summary>
/// <param name="controller">The controller.</param>
/// <param name="action">The action method.</param>
/// <param name="attributeType">Type of the attribute to look for.</param>
/// <returns>Returns true if the attribute was present on the action. Otherwise false.</returns>
public static bool VerifyControllerActionAttribute(this Controller controller, Func<ActionResult> action, Type attributeType)
{
    MethodInfo methodInfo = action.Method;
    object[] attributes = methodInfo.GetCustomAttributes(attributeType, true);
    return attributes.Any(a => a.GetType() == attributeType);
}

And the usage looks like this:

[TestMethod]
public void Index_ContainsTemplateLayoutAttribute()
{
    HomeController controller = new HomeController();
    bool containsAttribute = controller.VerifyControllerActionAttribute(controller.Index, typeof(TemplateLayoutAttribute));
    Assert.IsTrue(containsAttribute);
}

Need an introduction? Watch a video about unit testing ASP.NET and MVC based web apps on Vimeo, published by Typemock.

  • http://rhizohm.net Karsten Januszewski

    Nice code sample! Remember that if you are testing a method on a controller that has parameters, you’ll need to change the signature of the

    VerifyControllerActionAttribute so that the Func reflects those parameters.

    Aka, if you are testing homeController.Edit(int id) then the Func will have to look like Func

  • http://martinnormark.com/ Martin H. Normark

    I see, good point!

    Not as generic as I’d hoped then.