lithium.classloadertest.spring.UnfinalizingSpringTestRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of multiverse-test Show documentation
Show all versions of multiverse-test Show documentation
The Multiverse Test Framework for Java
The newest version!
package lithium.classloadertest.spring;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import lithium.classloadertest.FunctionalTestClassLoader;
import lithium.classloadertest.UnfinalizingTestRunner;
import lithium.classloadertest.common.TransformingURLClassLoader;
import org.junit.runners.model.InitializationError;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.test.context.TestContextManager;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* UnfinalizingSpringTestRunner which provides functionality of the
* Spring TestContext Framework to standard JUnit 4.5+ tests by means
* of the {@link TestContextManager} and associated support classes and annotations
* see {@link SpringJUnit4ClassRunner} and
* at the same time runs it in a different classloader providing unfinalized features
* see {@link UnfinalizingTestRunner}.
*
* @author eddie.lo
*/
public class UnfinalizingSpringTestRunner extends UnfinalizingTestRunner {
private static final Logger logger = LoggerFactory.getLogger(UnfinalizingSpringTestRunner.class);
/**
* Constructs a new SpringJUnit4ClassRunner
and initializes a
* {@link TestContextManager} to provide Spring testing functionality to
* standard JUnit tests.
* @param clazz the test class to be run
* @throws ClassNotFoundException
*/
public UnfinalizingSpringTestRunner(Class> clazz) throws InitializationError, ClassNotFoundException {
super(clazz);
if (logger.isDebugEnabled()) {
logger.debug("UnfinalizingSpringTestRunner constructor called with [" + clazz + "].");
}
}
/**
* Delegates to the parent implementation for creating the test instance and
* prepare the test instance before returning it.
* @see TestContextManager#prepareTestInstance(Object)
*/
@Override
protected Object createTest() throws Exception {
Object testInstance = super.createTest();
ClassLoader origClassLoader = Thread.currentThread().getContextClassLoader();
try {
TransformingURLClassLoader classLoader = getClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
Class> loadedClass = classLoader.loadClass(UnfinalizingSpringTestRunner.class.getName());
Object[] args = new Object[] {testInstance};
Method method = getMethodForArgs(loadedClass, "createTestContextManager", args);
method.invoke(null, args);
return testInstance;
} catch (Exception e) {
throw new RuntimeException("Failed to instantiate test class", e);
} finally {
if (origClassLoader != null) {
Thread.currentThread().setContextClassLoader(origClassLoader);
}
}
}
/**
* Copied from {@link FunctionalTestClassLoader}, should be refactor out later
*/
private HashMap>> methodCache = new HashMap>>();
private List getMethods(Class> clazz, String methodName) {
HashMap> classMethods = methodCache.get(clazz.getName());
if (classMethods == null) {
classMethods = new HashMap>();
methodCache.put(clazz.getName(), classMethods);
Method methods[] = clazz.getMethods();
for (Method method : methods) {
List methodsByName = classMethods.get(method.getName());
if (methodsByName == null) {
methodsByName = new ArrayList();
methodsByName.add(method);
classMethods.put(method.getName(), methodsByName);
}
}
}
return classMethods.get(methodName);
}
private Method getMethodForArgs(Class> loadedClass, String methodName, Object[] args) throws SecurityException,
NoSuchMethodException {
List methods = getMethods(loadedClass, methodName);
if (methods != null) {
for (Method method : methods) {
Class> paramTypes[] = method.getParameterTypes();
if (paramTypes.length == args.length) {
boolean isCompatible = true;
for (int i = 0; i < paramTypes.length; i++) {
Class> paramType = paramTypes[i];
Class> argType = args[i].getClass();
if (!paramType.isAssignableFrom(argType)) {
isCompatible = false;
break;
}
}
if (isCompatible) {
return method;
}
}
}
}
throw new RuntimeException("Could not find a method named " + methodName + " matching the arguments " + Arrays.toString(args));
}
/**
* Called reflectively by {@link #createTest()} to set up the Spring test context manager in the child
* classloader.
*
* @param testInstance - an instance of the class under test in the current ClassLoader
* @return a new TestContextManager
*/
public static TestContextManager createTestContextManager(Object testInstance) {
TestContextManager testContextManager = new TestContextManager(testInstance.getClass());
try {
testContextManager.prepareTestInstance(testInstance);
} catch (Exception e) {
throw new RuntimeException("Failed setting up Spring test instance", e);
}
return testContextManager;
}
}