How to unit test PostSharp aspects?
Asked Answered
S

2

13

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?

Straley answered 16/3, 2012 at 12:41 Comment(0)
H
10

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.
Haiku answered 16/3, 2012 at 12:48 Comment(3)
I fully agree with your "first part". About your "second part", I'm looking for code sample in order to understand "how this would look like" as this is the key-point of my question. I will investigate the Compile time validation according to your suggestion.Straley
@Straley I have updated my answer with a sample of how to separate the different task to make them testableHaiku
I get it. Decoupling is the key. Thanks a lot for your explicit example.Straley
V
1

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

Vitriolic answered 26/4, 2013 at 15:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.