14
votes

I'm wondering what the best way to do this is... I'm interested in introducing PostSharp into one of my projects, but I'm not sure how to unit test classes marked with an attribute properly.

For example:

public class hello {

    [MyAspectThatDoesSomethingToTheDatabaseWhenThisMethodGetsCalled]
    public int omg(string lol) {
        //fancy logic in here
    }
}

I'd like to test the logic in the omg() method, but in the unit tests I need to make sure that the aspect doesn't get called, because there isn't really a database.

Thoughts?

7

7 Answers

3
votes

I'm not entirely sure how postsharp works, but as I currently understand, you invoke a post build process to weave the aspects into the IL.

If my understanding is correct and if you can skip the post-build weaving then you should be testing your method in ignorance of the aspect ( and testing the aspect separately somewhere else ).

Why?

If you test the aspect and the method, you are testing 3 things at once:

  1. the method
  2. the aspect
  3. the weaving of the aspect into the code

This is bad karma and may lead you down the rabbit hole if something goes wrong ( as well as making your unit test into an integration test ).

Looking at the list above:

  • you do need to test the method, in isolation with no other distractions as this will let you focus on making sure the method does exactly what you expect - no more, no less.
  • you don't need to test the aspect every time it is used, just test it once and make sure it does what you think it does
  • you don't need to test that the weaving works; it is ( should be ) tested as part of the post sharp implementation.
3
votes

My opinion is that you should test the code as if the aspect were coded manually -- i.e. test the full functionality of the method, including the functionalities implemented by the aspect.

The question is now documented in PostSharp online documentation at http://doc.postsharp.net/postsharp-3.0/Content.aspx/PostSharp-3.0.chm/html/2ad6cf92-08eb-4537-a434-d88a3e493721.htm

2
votes

If you want to write pure UNIT test, consider disabling PostSharp for the module during UNIT TESTING builds by setting the compilation symbol 'SkipPostSharp' in your project, or set the MSBuild property 'SkipPostSharp=True'.

If you are happy to do integration test, you can test full functionality of your method and PostSharp attribute, including DB access (as suggested by Gael).

1
votes

I don't agree with Gael. I've learned from a friend that I must test the code that I'm going to write and in general only once.

1
votes

In order to turn off aspects related to database in my code, I introduced a static class called TestingEnvironment with a boolean property called TurnOffAspects. The code in aspect checks this property and if it is set to "true", the aspect returns without doing anything. During test setup I set TestingEnvironment.TurnOffAspects property to true, and during test teardown, back to false. Of course you can make things more granular introducing one property per each aspect you have. You should choose very carefully what aspects you turn off, since it can have a great impact on your test and make your production code fail even when test passes.

0
votes

Probably you can use dependency injection and introduce a static property for the aspect class where you decide which kind of database access provider you will use (e.g. using a factory), setting up the fake one in scope of a test.

0
votes

My current approach is to have the tests running as part of the build process on our TFS. This might not be helpful for all scenarios, but I've spent quite a while to find a solution that would allow me to run the unit tests of our business logic without any impacts of PostSharp.

I created two different build definitions, one of which has the MSBuild Arguments set to /p:SkipPostSharp=True (this is the one running the unit tests) and the other one to False respectively. Additionalliy, I set the Disable Testsoption to True for the build definition using PostSharp.

I know this isn't ideal (especially because now I've got the problem of not being able to run the tests locally without any changes), but I couldn't find any other way around it. It seems that there aren't too many people with the same problems. As I'm an absolute newbie in terms of MSBuild and its configuration, maybe someone with a better knowledge could help.

I also played around with the Configuration Manager in Visual Studio to create another build definition, but all my attempts only produced more problems than anything else.