Hi Wim,
I like your idea with @RestrictedVIsibility.
pointcut disallowedCalls() : !testCode() && (call(@OnlyForTesting *..*.new(..)) || call(@OnlyForTesting * *..*.*(..))) ;
declare error : disallowedCalls() : "this call is only allowed from test code!";
But sometimes you have methods which are indirect called from your test code and are @PublicForTesting:
pointcut belowTestMethods() : cflowbelow(execution(@Test * *..*())) || cflowbelow(execution(@Before * *..*())) || cflowbelow(execution(@BeforeClass * *..*())) || cflowbelow(execution(@After * *..*())) || cflowbelow(execution(@AfterClass * *..*())) || cflowbelow(execution(@OnlyForTesting * *..*())) || cflowbelow(execution(@OnlyForTesting *..new())) || cflowbelow(@within(OnlyForTesting)) ;
public pointcut applicationCode() : (call(@PublicForTesting * *..*(..)) || call(@PublicForTesting *..new(..))) && !belowTestMethods() ;
Unfortunately this can be not used inside 'declare error' (because of cflowbelow). So it is used in an after-advice:
after() : applicationCode() { if (Assertions.enabled) { String caller = getCallerClassName(); Signature sig = thisJoinPointStaticPart.getSignature(); String self = sig.getDeclaringTypeName(); assert self.equals(caller) : "only test methods or object itself may call " + JoinPointHelper.getAsShortString(thisJoinPoint); } }
As you can see it is only checked if assertions are enabled. So PatternTesting use not a RuntimeException here. An AssertionError will be thrown in case of a violation of incorrect use of the @PublicOnlyForTesting method.
regards Oliver
Am 05.01.2010 um 20:51 schrieb Wim Deblauwe: Hi,
I had the idea that it should be possible to use an annotation to declare custom visibility of a method that is really public. You could use this to annotate methods that have been made public for unit testing, or because you just need 1 particular class in another package to use it.
I just want to put down what I have got so far, maybe others can build on it or improve if they like the idea.
Idea #1: Restrict the calling of the public method to test code (assuming TestNG here)
1) Create an annotation called @TestingOnly and put that on any method that only should be called by testing code
2) The following aspect should do it: public aspect IllegalTestOnlyMethodCallChecker {
declare error: testCallOutsideTestCode(): "Don't call test methods outside test code!";
pointcut clientCall() : call(@TestingOnly * *(..))
&& !within(@org.testng.annotations.Test *)
&& !withincode(@org.testng.annotations.Test * *(..))
; }
Idea #2: Restrict the calling of a public method to only being called from an approved class
1) Create an annotation @RestrictedVisibility
@Retention(RetentionPolicy.RUNTIME) public @interface RestrictedVisibility {
Class allowedClass(); }
2) Use the annotation like this:
public class DomainObject {
@RestrictedVisibility(allowedClass = TestService.class) public void domainMethod() {
} }
This would mean that only TestService is allowed to call the method 'domainMethod'
3) Use this aspect
public aspect RestrictedVisibilityAspect {
pointcut callToRestricted(Object targetObject, Object callingObject):call( @RestrictedVisibility * *(..) )
&& target(targetObject) && this(callingObject); before(Object targetObject, Object callingObject) : callToRestricted(targetObject, callingObject)
{ System.out.println( thisJoinPointStaticPart.getSignature() ); System.out.println(targetObject); System.out.println(callingObject); Method m = ((MethodSignature)thisJoinPointStaticPart.getSignature()).getMethod();
RestrictedVisibility rv = m.getAnnotation(RestrictedVisibility.class); if( rv.allowedClass().equals( callingObject.getClass() )) { System.out.println( "It is ok!");
} else { System.out.println( "This call is not allowed!"); } }; }
Note that I was not able to use declare error anymore due to the use of this() and target(). You should ofcourse throw a RunTimeException instead of just printing something like I did here.
Is it possible to avoid the reflection and casting? Is anybody else using an Aspect simular to this?
regards,
Wim
_______________________________________________ aspectj-users mailing list aspectj-users@xxxxxxxxxxx https://dev.eclipse.org/mailman/listinfo/aspectj-users
|