
com.newmainsoftech.aspectjtuil.testutil.junit.JUnitAssistAspect Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of aspectjutil-testutil Show documentation
Show all versions of aspectjutil-testutil Show documentation
Utilities by AspectJ for unit test.
The newest version!
/*
* Copyright (C) 2012-2013 NewMain Softech
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
package com.newmainsoftech.aspectjtuil.testutil.junit;
import java.lang.reflect.UndeclaredThrowableException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.newmainsoftech.aspectjutil.adviseutil.Util;
/**
* Helper aspect for JUnit test.
*
* Usage example
*
* - To get test name
*
* - Background:
* In JUnit 3.x, the name of current test was easily obtained with JUnit's getName
method:
* String testName = this.getName();
* With JUnit 4, you need to use @Rule
or @Interceptor
annotation with
* TestName
class object.
*
*
* - By just adding this JUnitAssistAspect class (aspectjutil-testutil.jar) to the project's aspect-path
* (and, of course, AspectJ's runtime library, SLF4J's API jar and binding jar files in runtime classpath,
* additionally to either compiling with AJC for CTW or aop.xml for LTW), no matter the version of JUnit
* you're using, the name of the current test can be simply obtained by:
*
* String testName = JUnitAssistAspect.getTestName();
*
* For further info, see {@link #getTestName()}
method.
*
*
* - Limitation
* If your test method spawning other thread, and call {@link #getTestName()}
method from
* spawned thread, then it will return null as test name instead of actual test name.
*
*
*
* - To log entrance and exit of test
* By just adding this JUnitAssistAspect class (aspectjutil-testutil.jar) to the project's aspect-path,
* entrance and exit of test will be logged like:
*
*
* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
* STARTS TEST: test_SysPropExt_addText
* ...
* ENDS TEST: test_SysPropExt_addText
* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
*
*
*
*
*
* @author Arata Y.
*/
@Aspect
public class JUnitAssistAspect {
private static ThreadLocal testNameThreadLocal
= new ThreadLocal();
protected static ThreadLocal getTestNameThreadLocal() {
return testNameThreadLocal;
}
/**
* Get name of running test.
* This works as long as being called from main thread running each JUnit test even multiple
* JUnit tests running concurrently.
* But this does not work when called from child worker thread spawned during a test. To support
* the call from child worker thread spawned during a test, you may make your test class implemented
* {@link JUnitAssistContract} interface and implement custom logic for
* {@link JUnitAssistContract#getRunningTestName()} method.
* @return name of running test, or null when called from child thread spawned during test.
*/
public static String getTestName() {
String testName = null;
MethodSignature methodSignature = testNameThreadLocal.get();
if ( methodSignature == null) {
// Avoid memory leakage for either case of having called not during test by mistake
// or having called from thread spawned during test
testNameThreadLocal.remove();
}
else {
testName = testNameThreadLocal.get().getName();
if ( testName == null) {
// Avoid memory leakage for either case of having called not during test by mistake
// or having called from thread spawned during test
testNameThreadLocal.remove();
}
}
return testName;
}
/** Dummy method for {@link Pointcut} what cross-cut execution of test method. */
@Pointcut( value="execution( @org.junit.Test * *.*()) || execution( * junit.framework.TestCase+.test*())")
public static void pointcutOnExecutionOfJUnitTestMethod() {}
/** Dummy method for {@link Pointcut} what cross-cut below execution of test method. */
@Pointcut( value="cflowbelow( pointcutOnExecutionOfJUnitTestMethod())")
public static void pointcutOnSubsequentialExecutionOfJUnitTestMethod() {}
/**
* Dummy method for {@link Pointcut} what cross-cut top most execution of test method.
* This Pointcut
is advised by
* {@link #beforeAdvisedTopMostExecutionOfJUnitTestMethod(JoinPoint)} and
* {@link #afterAdvisedTopMostExecutionOfJUnitTestMethod(JoinPoint)}.
*/
@Pointcut( value="pointcutOnExecutionOfJUnitTestMethod() "
+ "&& !pointcutOnSubsequentialExecutionOfJUnitTestMethod() "
+ "&& !execution( @org.junit.Ignore * *.*()) "
+ "&& !cflow( adviceexecution())")
public static void pointcutOnTopMostExecutionOfJUnitTestMethod() {}
/**
* {@link Before} advise method to preserve test method name and to log entrance of test method.
* There shouldn't be necessity of calling this method intentionally.
*
* @param joinPoint
* @throws Throwable
* @see JUnitAssistAspect#pointcutOnTopMostExecutionOfJUnitTestMethod()
*/
@Before( value="pointcutOnTopMostExecutionOfJUnitTestMethod()")
public void beforeAdvisedTopMostExecutionOfJUnitTestMethod( JoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature)(joinPoint.getSignature());
JUnitAssistAspect.getTestNameThreadLocal().set( methodSignature);
Object target = joinPoint.getTarget();
Class> targetClass = target.getClass();
if ( target instanceof JUnitAssistContract) {
JUnitAssistContract jUnitAssist = (JUnitAssistContract)target;
try {
jUnitAssist.setRunningTestName( methodSignature.getName());
}
catch( Throwable throwable) {
if ( Util.isExceptionChecked( methodSignature, throwable)) {
throw throwable;
}
else {
throw new UndeclaredThrowableException(
throwable,
String.format(
"Occured at beforeAdvisedTopMostExecutionOfJUnit4TestMethod "
+ "advise method of %1$s aspect",
JUnitAssistAspect.class.toString()
)
);
}
}
}
// Log entrance to test method
Logger logger = LoggerFactory.getLogger( target.getClass());
if ( logger.isInfoEnabled()) {
logger.info(
String.format(
"%n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>%n"
+ "STARTS TEST: %1$s",
methodSignature.getName()
)
);
}
}
/**
* {@link After} advise method to log exit of test method.
* There shouldn't be necessity of calling this method intentionally.
*
* @param joinPoint
* @see JUnitAssistAspect#pointcutOnTopMostExecutionOfJUnitTestMethod()
*/
@After( value="pointcutOnTopMostExecutionOfJUnitTestMethod()")
public void afterAdvisedTopMostExecutionOfJUnitTestMethod( JoinPoint joinPoint) {
// Log exit from test method
Logger logger = LoggerFactory.getLogger( joinPoint.getTarget().getClass());
if ( logger.isInfoEnabled()) {
logger.info(
String.format(
"%nENDS TEST: %1$s%n"
+ "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
JUnitAssistAspect.getTestName()
)
);
}
JUnitAssistAspect.getTestNameThreadLocal().remove();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy