Yes it certainly makes sense to unit tests aspects, since they represent functionality and since you are using it in more than one place it is even more important to test it.
However you have to devide this into two parts:
- Testing the actual aspect functionality
- Testing whether context extraction is working properly that is used to actually execute the aspect functionality
For the first part, if you have decoupled the actual functionality from the attribute that executes the aspect functionality properly, creating unit tests should be no different than unit testing normal code.
For the second part you need to decouple the extraction of context as well, this might seem like overkill but if you wanne unit test it properly you will need todo it I'm afraid.
On that note you should also make use of compile time validation, which can also prevents you from using the attributes in the wrong way. Sometimes it's necessary to test certain conditions that you can not describe with the Attribute syntax, then compile time validation comes into play. This has been a great asset for me and reduced the amount of debugging sessions in regards to PostSharp aspects significantly, see:
http://www.sharpcrafters.com/postsharp/robustness
Here is some very basic sample code, no DI nothing, just to illustrate how to split things up:
public sealed class TraceAttribute : OnMethodBoundaryAspect
{
private readonly string category;
private TraceArgumentService argumentService;
private TraceService traceService;
public string Category { get { return category; } }
public TraceAttribute(string category)
{
this.category = category;
}
public override void RuntimeInitialize(System.Reflection.MethodBase method)
{
base.RuntimeInitialize(method);
this.argumentService = new TraceArgumentService();
this.traceService = new TraceService();
}
public override void OnEntry(MethodExecutionArgs args)
{
traceService.Write(
argumentService.GetDeclaringTypeName(args),
argumentService.GetMethodName(args),
category);
}
}
public class TraceArgumentService
{
public string GetDeclaringTypeName(MethodExecutionArgs args)
{
return args.Method.DeclaringType.Name;
}
public string GetMethodName(MethodExecutionArgs args)
{
return args.Method.Name;
}
}
public class TraceService
{
public void Write(string declaringTypeName, string methodName, string category)
{
Trace.WriteLine(string.Format("Entering {0}.{1}.",
declaringTypeName, methodName), category);
}
}
You might ask why TraceService
and a separate TraceArgumentService
:
- The Tracing logic should be independent from PostSharp, therefore it should not be knowing about
MethodExecutionArgs
.
- Extracting the arguments from
MethodExecutionArgs
is not part of Tracing, it's more related to the aspect. Since you want to be able to test it, you need to somehow separate it.