Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test PostSharp aspects?

After asking this question about implementing an aspect with PostSharp, it came to my mind that I might have to update the code of this aspect in the future, and that I did not want to take the risk of breaking everything afterwards.

So, I started thinking about unit testing.

My first question is:

Is it relevant to think about unit testing an aspect?

I would like the answer to be "yes", but if not, I expect getting other advices.

And then, if so,

How to implement unit testing for PostSharp aspects?

like image 700
remio Avatar asked Mar 16 '12 12:03

remio


2 Answers

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:

  1. Testing the actual aspect functionality
  2. 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.
like image 148
ntziolis Avatar answered Nov 07 '22 15:11

ntziolis


The question is now addressed in PostSharp reference documentation:

http://doc.postsharp.net/postsharp-3.0/Content.aspx/PostSharp-3.0.chm/html/2ad6cf92-08eb-4537-a434-d88a3e493721.htm

like image 23
Gael Fraiteur Avatar answered Nov 07 '22 15:11

Gael Fraiteur