0

I have a class like the following:

[Log]
public class SomeClass
{  }

With the LogAttribute being an OnMethodBoundaryAspect from PostSharp. I would like to have all instances of LogAttribute to be swapped out for some faked/mocked version of the aspect that does nothing so that I can unit test SomeClass independently of the aspect code running. I will leave the aspect functioning normally during my integration tests. Does anyone know how to achieve something similar to this?

Note that this project is using Moq for the unit testing and Ninject for DI outside of the unit test project.

Thanks!

cjablonski76
  • 173
  • 1
  • 13
  • 2
    possible duplicate of [How do you disable PostSharp when running unit tests?](http://stackoverflow.com/questions/14691554/how-do-you-disable-postsharp-when-running-unit-tests) – Tomas Walek Apr 01 '14 at 15:28

2 Answers2

2

See this question How do you disable PostSharp when running unit tests?

You can tell PostSharp not to compile in the aspect for your unit-tests.

Community
  • 1
  • 1
detroitpro
  • 3,853
  • 4
  • 35
  • 64
  • I disable PostSharp in my UnitTest project, but the project it is testing has to have it enabled. I am still getting the PostSharp aspect code running inside the project being tested, should disabling PostSharp in my UnitTest project also disable it in the project being tested? – cjablonski76 Apr 01 '14 at 15:42
  • With this approach you need to build your project under test with a special build configuration for unit testing. You can use the standard Debug configuration or create your own. You need to disable PostSharp only for this build configuration, and leave it enabled for the Release build. – AlexD Apr 04 '14 at 15:34
0

If your logging aspect somewhat follows the PostSharp tutorials, then it should be writing to System.Diagnostics.Trace.

Assuming that is true, you just need to configure your DI framework to not register a TextWriter (or System Logging, or similar...) in Trace when running your tests; this lets the aspects fire and behave as they normally would at runtime, and they still write to Trace, you just don't have all the disk IO going on (because you didn't register a Stream Writer in System.Diagnostics.Trace).

I have used that successfully with my live logging aspect and not had issues with my SUTs or mocks. I also added a couple stubs with a couple simple methods, some decorated with aspects, some not. I then verified that the live aspect behaved as expected (Assert.Throws<MyWrappedException> for example). These stubs allowed me to isolate down so that the Aspect was the SUT everything else was mocked, and I could assert the aspect behaved as I expected. That was a while ago, I probably could have used Moq instead of the fakes, but there has been no reason to change that code; they help verify my aspect was thread-safe.


As another option, you can add a stub or fake that inherits from OnMethodBoundaryAspect, and have your CI register it as your Aspect at test runtime instead of your live aspect. This lets you leave the guts empty or near-empty if your live aspect isn't writing to Trace, or if you cannot exclude registering the System Logging or a TextWriter in Trace at test time. You then control the guts of the stubbed methods and decide what should be recorded in memory for later retrieval / assertion and what should just simply be ignored.

Because those methods are #protected, Moq isn't going to be happy about it; To a pure Moq'ist this can feel painful or ugly, but, in this case you're talking about only one fake class, and it will coexist nicely with your Moqs. Additionally, it lets you isolate your tests to your SUTs ignoring the aspects, so it helps narrow your tests down to the class and behavior you care about.

Store that stubbed or fake class in the same project as your tests, and then configure your DI to instantiate your stub at test runtime instead of your real aspect. PostSharp will still properly inject into your SUTs at compile-time, and asserts should still succeed if you code the stub

Damon
  • 1,249
  • 1
  • 15
  • 27
  • I am not actually trying to replace the [Log] aspect, just any PostSharp aspects in general. So I am attempting to have my DI bind my own "empty" aspect for any `OnMethodBoundary` aspects. I need the PostSharp aspect to ideally not run any code, but if possible at least not call the RuntimeInitialize function. By injecting my overridden `OnMethodBoundaryAspect` class, the live PostSharp aspects are still running their RuntimeInitialize functions. Should injecting my `OnMethodBoundaryAspect` be forcing my empty RuntimeInitialize implementation to be getting ran? – cjablonski76 Apr 03 '14 at 16:17
  • Let me hack on it a bit over the weekend and I'll have some code snippets for you; I thought I had some already in some demo code, but no. The issue I think you're hitting is at compile-time, your live Log aspect is being used (and thus woven into your source), so runtime, it will still fire the `RuntimeInitializations` on it, not your FakeLog. Let me know if I'm off on that. – Damon Apr 03 '14 at 16:39
  • Sounds right to me, so short of getting PostSharp to be disabled, there needs to be some way to have the FakeLog woven in at compile time... – cjablonski76 Apr 03 '14 at 16:44
  • yah exactly; then you can do whatever you want with FakeLog. I've done something similar in the past, I just need to play around with it a bit to get a demo. Outside of that, you could use a mocking framework that allows runtime intercepts, like TypeMock, but I hate going to that extreme... but that would let you intercept any call to RuntimeInitialize and tell it to do nothing. – Damon Apr 03 '14 at 16:46
  • TypeMock might not be an option for the client this is for, but I will definitely look in to it. – cjablonski76 Apr 03 '14 at 18:06
  • If you want to use DI at run-time to enable/disable the aspect, then you need to create your own `OnMethodBoundaryAspect` that only delegates all calls to the real aspect provided by the DI container. This should be pretty straightforward - the methods like OnEntry, OnSuccess, etc. will just ask the container for the required instance and invoke corresponding method. More about using aspects with DI: http://doc.postsharp.net/content/consuming-dependencies – AlexD Apr 04 '14 at 15:41