Testing your device with AOP / PostSharp

I am trying to use PostSharp to implement a security aspect to apply method-level authorization checks at my repository level.

The concept is outlined here .

However, these authorization checks interfere with unit testing, making them more integrated.

What would be the best way to isolate them as unit tests , essentially ignoring / mocking the security aspect so that I can simply check the actual behavior of the class without having to initialize a bunch of security information?

Is AOP associated with unit testing?

+4
source share
3 answers

To answer your second question in the first place, no, AOP does not essentially conflict with unit testing. Usually, Id best describes unit test methods and aspects separately.

There are several options in your case.

The easiest way is to simply install the unit test installation method so that the stream has the necessary permissions.

If you do not want to do this, you can distinguish two ways for your unit test. The first is to extract all the code from the methods used for security aspects into separate methods, for example:

[SecurityAspect] void DoSomething() { DoSomethingInternal(); } void DoSomethingInternal() { // this is the real code } 

You can then run your unit tests against all unprotected internal methods that test the logic in them without worrying about security.

A second approach would be to introduce a mock permission tester into the aspect itself. To be able to do this, you will need to define a separate class and interface that implements the actual security testing logic, something like this (assuming you are passing a stream to check security):

 public interface IPermissionsChecker { bool HasPermissions(Thread thread); } 

This is your access control for your live system:

 public class RealPermissionsChecker : IPermissionsChecker { public bool HasPermissions(Thread thread) { // do your real work here } } 

And this is the one you use in your unit tests

 public class MockPermissionsChecker : IPermissionsChecker { public bool HasPermissions(Thread thread) { return true; } } 

Now you need to define your aspect as follows:

 public class SecurityChecker : OnMethodBoundaryAspect { IPermissionsChecker _checker; public override void OnEntry(MethodExecutionArgs args) { if (!_checker.HasPermissions(Thread.CurrentThread)) throw new SecurityException("No permissions"); } } 

The only remaining problem is the need to insert the correct permission check into the aspect.

A little hacky way I did this before is to make the _checker static field and provide a static method to initialize it:

 public class SecurityChecker : OnMethodBoundaryAspect { private static IPermissionsChecker _checker; public static void InjectChecker(IPermissionsChecker checker) { // best put some code here to make sure this is only called once, // as well as doing thread synchronization if (_checker == null) _checker = checker; } 

The fact that InjectChecker is static means that you can access it from your application launch (or unit test startup). I suspect that unit test purists will frown on this - and you need to make sure that you call it when the application starts, but I think that this is the easiest way to insert a checker into an aspect, bypass the fact that the rest of your code cannot access instance instances directly.

A more complicated alternative is to override RunTimeInitialize () in your aspect - this method is called by PostSharp when the aspect is initialized. You would probably do something like this:

  public override void RuntimeInitialize(MethodBase method) { base.RuntimeInitialize(); this._checker =PermissionsCheckerProvider.Current.GetChecker(); } 

You will see that you need to define another class:

 public class PermissionsCheckerProvider { // make sure you set this at app startup, either to the mock or to the real checker public static PermissionsCheckerProvider Current { get; set;} public IPermissionsChecker GetChecker() { } } 

This approach ensures that the method tries to initialize it at the right time, but then you had a problem in that you provided the appropriate current provider before the aspect tried to initialize. Therefore, I personally will probably come up for the first approach, so that everything is simple.

This discusses the issue of dependency injection and RuntimeInitialize. https://codereview.stackexchange.com/questions/20341/inject-dependency-into-postsharp-aspect

+4
source

Two links that broadly answer your question:

+2
source

If you use Typemock in your unit tests, you can use something like

 MyAspect myAspectMock = Isolate.Fake.Instance<MyAspect>(Members.MustSpecifyReturnValues); Isolate.Swap.AllInstances<MyAspect>().With(myAspectMock); 

This allows you to control which tests are used in aspects and which are not, allowing you to test the method itself and with the help of tips.

Presumably, a similar mechanism will exist with other mocking frames.

0
source

Source: https://habr.com/ru/post/1485068/


All Articles