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));
                        }
                    }
                }
            }
        }
    }
}