I’m using PostSharp on a project, with a custom aspect that provides standard handling for authentication and authorisation.

To ensure that all our service methods are properly annotated with our custom aspect (there are only a couple of service calls that shouldn’t have the attribute present) I wrote a unit test:

public void PublicMethods_MustHaveSecurity()
    var facade = typeof(Facade);
    var violatingMethods
        = typeof(IFacade).Assembly.GetExportedTypes()
            .Where(t => t.IsClass)
            .Where(t => facade.IsAssignableFrom(t))
                c => c.GetMethods(
                    BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance))
                m => m.GetCustomAttributes(
                    typeof(AuthenticatedServiceAttribute), false).Count() == 0)
    var message
        = violatingMethods.Select(m => string.Format("{0}.{1}", m.DeclaringType.Name, m.Name))
            .JoinWith("; ");
    Assert.That(violatingMethods.Count, Is.EqualTo(0), "Found " + message);

Let’s walk through to see how this works.

We find the assembly containing all our service method facades, and from this assembly find all exported types that are classes descending from Facade. From each facade class, we select all the public methods and check each to see if our custom aspect is present, keeping only the methods that are not decorated.

Given the list of violatingMethods, we select the class qualitifed name of each method, joining them all together with “; “.

Easy. Well, easier to read than to write anyway.

There was one final trick required to make this work - by default, PostSharp will remove the aspect attributes after processing. I needed to add a MulticastAttributeUsage attribute to the aspect to configure PostSharp to leave the attribute in place:

[MulticastAttributeUsage(MulticastTargets.Method, PersistMetaData = true)]
public class AuthenticatedServiceAttribute : OnMethodBoundaryAspect

This is just one - very specific - example of what you can do with Linq and a unit test, checking to ensure that a desired convention is correctly applied.


blog comments powered by Disqus