Category Archives: Unit testing

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.

Unit test for verifying references from DataAnnotation validation to the ErrorMessageResourceName value

I love the new model validation features in System.ComponentModel.DataAnnotations. One thing I don’t like though, is that the ErrorMessageResourceName is loosely typed. The ErrorMessageResourceType, however, is a System.Type which will be strongly typed by assigning its value using the typeof(Namespace.ResourceSetType) method.

Since there’s no build-breaking reference between a resource file and the value of the ErrorMessageResourceName on all classes where you use it, I thought it would be cool to have a unit test that verifies the existence of all referenced resource keys.

Remember to add a reference to System.ComponentModel.DataAnnotations.

Code

/// <summary>
/// Verifies that all properties that are decorated with validation data-annotations, refers to 
/// an existing resource. This will make sure, that missing resources are not referenced.
/// </summary>
[TestMethod]
public void All_Properties_With_Validation_Annotations_Must_Refer_To_Existing_Resource()
{
    Assembly assembly = Assembly.Load(new AssemblyName("MyApp.Model.Namespace"));
    var types = assembly.GetTypes().Where<Type>(t => t.IsClass && !t.IsAbstract);

    foreach (var type in types)
    {
        var properties = type.GetProperties();

        foreach (PropertyInfo property in properties)
        {
            var attributes = property.GetCustomAttributes(true);

            foreach (var item in attributes)
            {
                if (item is ValidationAttribute)
                {
                    ValidationAttribute val = item as ValidationAttribute;

                    Assert.IsNotNull(val);

                    if (val.ErrorMessageResourceType != null)
                    {
                        Assert.AreNotEqual(String.Empty, val.ErrorMessageResourceName,
                            String.Format(@"Validation Error Resource specified on property:
                        {0}.{1} is empty!", type.ToString(), property.Name));

                        try
                        {
                            ResourceManager rm = new ResourceManager(val.ErrorMessageResourceType);
                            string resourceValue = rm.GetString(val.ErrorMessageResourceName);
                            Assert.IsFalse(String.IsNullOrEmpty(resourceValue),
                                String.Format(@"The value of the Validation Error Resource specified on property:
                            {0}.{1} is empty!", type.ToString(), property.Name));
                        }
                        catch (MissingManifestResourceException)
                        {
                            Assert.Fail(String.Format(@"Validation Error Resource specified on property:
                            {0}.{1} could not be found!", type.ToString(), property.Name));
                        }
                    }
                }
            }
        }
    }
}