org.powermock.modules.junit4.rule.PowerMockRule Maven / Gradle / Ivy
/*
* Copyright 2010 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.rule;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
import org.powermock.core.MockRepository;
import org.powermock.core.agent.JavaAgentClassRegister;
import org.powermock.core.agent.JavaAgentFrameworkRegister;
import org.powermock.core.agent.JavaAgentFrameworkRegisterFactory;
import org.powermock.modules.agent.PowerMockAgent;
import org.powermock.modules.agent.support.JavaAgentClassRegisterImpl;
import org.powermock.modules.agent.support.PowerMockAgentTestInitializer;
import org.powermock.reflect.Whitebox;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Set;
public class PowerMockRule implements MethodRule {
static {
if (PowerMockRule.class.getClassLoader() != ClassLoader.getSystemClassLoader()) {
throw new IllegalStateException("PowerMockRule can only be used with the system classloader but was loaded by " + PowerMockRule.class.getClassLoader());
}
PowerMockAgent.initializeIfPossible();
}
@Override
public Statement apply(Statement base, FrameworkMethod method, Object target) {
JavaAgentClassRegister agentClassRegister = new JavaAgentClassRegisterImpl();
PowerMockAgentTestInitializer.initialize(target.getClass(), agentClassRegister);
return new PowerMockStatement(base, target, agentClassRegister);
}
}
class PowerMockStatement extends Statement {
private static final String ANNOTATION_ENABLER = "org.powermock.api.extension.listener.AnnotationEnabler";
private final Statement fNext;
private final Object target;
private final JavaAgentClassRegister agentClassRegister;
private final JavaAgentFrameworkRegister javaAgentFrameworkRegister;
public PowerMockStatement(Statement base, Object target, JavaAgentClassRegister agentClassRegister) {
this.fNext = base;
this.target = target;
this.agentClassRegister = agentClassRegister;
this.javaAgentFrameworkRegister = JavaAgentFrameworkRegisterFactory.create();
}
@Override
public void evaluate() throws Throwable {
Object annotationEnabler = loadAnnotationEnableIfPresent();
try {
injectMocksUsingAnnotationEnabler(target, annotationEnabler);
setFrameworkAgentClassRegister();
fNext.evaluate();
} finally {
// Clear the mock repository after each test
MockRepository.clear();
clearMockFields(target, annotationEnabler);
clearFrameworkAgentClassRegister();
}
}
private void clearFrameworkAgentClassRegister() {
agentClassRegister.clear();
javaAgentFrameworkRegister.clear();
}
private void setFrameworkAgentClassRegister() {
javaAgentFrameworkRegister.set(agentClassRegister);
}
private Object loadAnnotationEnableIfPresent() {
boolean hasAnnotationEnabler = hasAnnotationEnablerClass();
if (!hasAnnotationEnabler) {
return null;
}
try {
return Whitebox.invokeConstructor(Class.forName(ANNOTATION_ENABLER, true, Thread.currentThread().getContextClassLoader()));
} catch (Exception e) {
throw new RuntimeException("PowerMock internal error, failed to load annotation enabler.");
}
}
private boolean hasAnnotationEnablerClass() {
try {
Class.forName(ANNOTATION_ENABLER, false, Thread.currentThread().getContextClassLoader());
return true;
} catch (ClassNotFoundException e) {
return false;
}
}
private void clearMockFields(Object target, Object annotationEnabler) throws Exception {
if (annotationEnabler != null) {
Class extends Annotation>[] mockAnnotations = Whitebox.invokeMethod(annotationEnabler, "getMockAnnotations");
Set mockFields = Whitebox.getFieldsAnnotatedWith(target, mockAnnotations);
for (Field field : mockFields) {
field.set(target, null);
}
}
}
private void injectMocksUsingAnnotationEnabler(Object target, Object annotationEnabler) throws Exception {
if (annotationEnabler != null) {
Whitebox.invokeMethod(annotationEnabler, "beforeTestMethod", new Class>[]{Object.class, Method.class,
Object[].class}, target, null, null);
}
}
}