org.powermock.modules.junit4.internal.impl.DelegatingPowerMockRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of powermock-module-junit4 Show documentation
Show all versions of powermock-module-junit4 Show documentation
PowerMock support module for JUnit 4.x.
/*
* Copyright 2013 the original author or authors.
*
* 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 org.powermock.modules.junit4.internal.impl;
import org.junit.Test;
import org.junit.experimental.theories.Theory;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.Filterable;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.notification.RunNotifier;
import org.powermock.core.spi.PowerMockTestListener;
import org.powermock.core.testlisteners.GlobalNotificationBuildSupport;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.powermock.modules.junit4.PowerMockRunnerDelegate.SinceJUnit_4_5;
import org.powermock.modules.junit4.common.internal.PowerMockJUnitRunnerDelegate;
import org.powermock.modules.junit4.common.internal.impl.JUnitVersion;
import org.powermock.reflect.Whitebox;
import org.powermock.reflect.exceptions.ConstructorNotFoundException;
import org.powermock.tests.utils.PowerMockTestNotifier;
import org.powermock.tests.utils.impl.PowerMockTestNotifierImpl;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
public class DelegatingPowerMockRunner extends Runner
implements PowerMockJUnitRunnerDelegate, Filterable {
private final String testClassName;
private final Runner delegate;
private final ClassLoader testClassLoader;
private final Method[] testMethods;
private final PowerMockTestNotifier powerMockTestNotifier;
public DelegatingPowerMockRunner(Class> klass) throws Throwable {
this(klass, null);
}
public DelegatingPowerMockRunner(Class> klass, String[] methodsToRun)
throws Throwable {
this(klass, methodsToRun, null);
}
public DelegatingPowerMockRunner(
Class> klass, String[] methodsToRun, PowerMockTestListener[] listeners)
throws Exception {
testClassName = klass.getName();
delegate = createDelegate(klass);
testClassLoader = klass.getClassLoader();
testMethods = determineTestMethods(klass, methodsToRun);
powerMockTestNotifier = new PowerMockTestNotifierImpl(listeners == null ? new PowerMockTestListener[0] : listeners);
}
private static Method[] determineTestMethods(
Class> testClass, String[] testMethodNames) {
List testMethods = new ArrayList();
for (Method m : testClass.getMethods()) {
if (m.isAnnotationPresent(Test.class) || m.isAnnotationPresent(Theory.class)) {
testMethods.add(m);
}
}
if (testMethods.isEmpty()) {
for (String testMethodName : testMethodNames) {
try {
testMethods.add(testClass.getMethod(testMethodName));
} catch (NoSuchMethodException ignore) {
System.err.println(ignore.getMessage());
}
}
}
return testMethods.toArray(new Method[testMethods.size()]);
}
private static Runner createDelegate(final Class> testClass)
throws Exception {
/*
* Because of the mockito integration it seems like it is necessary to
* set context classloader during delegate creation ...
*/
return withContextClassLoader(testClass.getClassLoader(),
new Callable() {
@Override
public Runner call() throws Exception {
try {
return Whitebox.invokeConstructor(
testClass.isAnnotationPresent(PowerMockRunnerDelegate.class)
? testClass.getAnnotation(PowerMockRunnerDelegate.class).value()
: PowerMockRunnerDelegate.DefaultJUnitRunner.class,
new Class[] {Class.class},
new Object[] {testClass});
} catch (ConstructorNotFoundException rootProblem) {
if (testClass.isAnnotationPresent(PowerMockRunnerDelegate.class)
&& JUnitVersion.isGreaterThanOrEqualTo("4.5")) {
try {
return Whitebox.invokeConstructor(testClass.getAnnotation(PowerMockRunnerDelegate.class).value(),
SinceJUnit_4_5.runnerAlternativeConstructorParams(),
new Object[] {
testClass,
SinceJUnit_4_5.newRunnerBuilder()
});
} catch (ConstructorNotFoundException ignoredWorkAroundFailure) {
}
}
throw rootProblem;
}
}
});
}
private static T withContextClassLoader(
ClassLoader loader, Callable callable) throws Exception {
final ClassLoader originalClassLoaderBackup =
Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(loader);
return callable.call();
} finally {
Thread.currentThread().setContextClassLoader(originalClassLoaderBackup);
}
}
@Override
public void run(final RunNotifier notifier) {
try {
withContextClassLoader(testClassLoader, new Callable() {
@Override
public Void call() {
PowerMockRunNotifier powerNotifier = new PowerMockRunNotifier(
notifier, powerMockTestNotifier, testMethods);
try {
GlobalNotificationBuildSupport.prepareTestSuite(
testClassName, powerNotifier);
delegate.run(powerNotifier);
} finally {
GlobalNotificationBuildSupport
.closePendingTestSuites(powerNotifier);
}
return null;
}
});
} catch (Exception cannotHappen) {
throw new Error(cannotHappen);
}
}
@Override
public Description getDescription() {
return delegate.getDescription();
}
@Override
public int getTestCount() {
return delegate.testCount();
}
@Override
public Class> getTestClass() {
return getDescription().getTestClass();
}
@Override
public void filter(Filter filter) throws NoTestsRemainException {
if (this.delegate instanceof Filterable) {
((Filterable) this.delegate).filter(filter);
}
}
}