Well since my initial attempt, I have now refactored the AssertDataAnnotation class to be slightly more user friendly. The property type is now inferred by the compiler and I’ve moved the ValidationAttribute type to the class definition.

using System;  
using System.ComponentModel.DataAnnotations;  
using System.Linq.Expressions;  
using System.Reflection;  
using Xunit;

public class AssertDataAnnotation<TType, TValidationAttribute> : Assert  
where TType : class  
where TValidationAttribute : ValidationAttribute  
{
public static void ContainsAttribute&lt;TProp&gt;(Expression<Func<TType, TProp>> expression)  
{
MemberInfo member = GetMember(expression);  
True(Attribute.IsDefined(member, typeof(TValidationAttribute)));  
}

public static void ErrorMessageEquals<TProp>(Expression<Func<TType, TProp>> expression, string expectedError)  
{
MemberInfo member = GetMember(expression);  
var attribute = Attribute.GetCustomAttribute(member, typeof(TValidationAttribute)) as ValidationAttribute;  
Equal(expectedError, attribute.ErrorMessage);  
}

private static MemberInfo GetMember<TProp>(Expression<Func<TType, TProp>> expression)  
{
var memberExpression = expression.Body as MemberExpression;  
if (memberExpression == null)  
throw new MissingMemberException("Property is invalid");

var member = memberExpression.Member;  
if (member.MemberType != MemberTypes.Property)  
throw new MissingMemberException(member.DeclaringType.Name, member.Name);  
return member;  
}
}

So now my validation attribute tests look like this

[Fact]
public void NameHasRequiredAttribute()  
{
AssertDataAnnotation<Country, RequiredAttribute>.ContainsAttribute(x => x.Name);  
}

[Fact]
public void NameHasRequiredAttributeWithErrorMessage()  
{
AssertDataAnnotation<Country, RequiredAttribute>.ErrorMessageEquals(x => x.Name, "Name is required");  
}

Nice and clean.