org.powermock.modules.testng.internal.TestClassInstanceFactory Maven / Gradle / Ivy
/*
* Copyright 2016 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.testng.internal;
import javassist.util.proxy.ProxyFactory;
import org.powermock.modules.testng.PowerMockTestCase;
import org.powermock.reflect.Whitebox;
import org.powermock.tests.utils.impl.MockPolicyInitializerImpl;
import java.lang.reflect.Constructor;
class TestClassInstanceFactory {
private final Constructor constructor;
private final Class> testClass;
private final Object[] params;
private final ClassLoader mockLoader;
TestClassInstanceFactory(Constructor constructor, TestNGMockClassLoaderFactory classLoaderFactory, Object... params) {
this.constructor = constructor;
this.params = params;
this.testClass = constructor.getDeclaringClass();
this.mockLoader = classLoaderFactory.createClassLoader(testClass);
}
Object create() {
try {
initializeMockPolicy();
final Class> testClassLoadedByMockedClassLoader = createTestClass(testClass);
final Constructor> con = testClassLoadedByMockedClassLoader.getConstructor(constructor.getParameterTypes());
final Object testInstance = con.newInstance(params);
if (!extendsPowerMockTestCase(testClass)) {
setInvocationHandler(testInstance);
}
return testInstance;
} catch (Exception e) {
throw new RuntimeException(String.format("Cannot create a new instance of test class %s", testClass), e);
}
}
private void initializeMockPolicy() {new MockPolicyInitializerImpl(testClass).initialize(mockLoader);}
/**
* We proxy the test class in order to be able to clear state after each
* test method invocation. It would be much better to be able to register a
* testng listener programmtically but I cannot find a way to do so.
*/
private Class> createTestClass(Class> actualTestClass) throws Exception {
final Class> testClassLoadedByMockedClassLoader = Class.forName(actualTestClass.getName(), false, mockLoader);
if (extendsPowerMockTestCase(actualTestClass)) {
return testClassLoadedByMockedClassLoader;
} else {
return createProxyTestClass(testClassLoadedByMockedClassLoader);
}
}
private Class> createProxyTestClass(Class> testClassLoadedByMockedClassLoader) throws Exception {
Class> proxyFactoryClass = Class.forName(ProxyFactory.class.getName(), false, mockLoader);
final Class> testNGMethodFilterByMockedClassLoader = Class.forName(TestNGMethodFilter.class.getName(), false, mockLoader);
Object f = proxyFactoryClass.newInstance();
Object filter = testNGMethodFilterByMockedClassLoader.newInstance();
Whitebox.invokeMethod(f, "setFilter", filter);
Whitebox.invokeMethod(f, "setSuperclass", testClassLoadedByMockedClassLoader);
return Whitebox.invokeMethod(f, "createClass");
}
private void setInvocationHandler(Object testInstance) throws Exception {
Class> powerMockTestNGMethodHandlerClass = Class.forName(PowerMockTestNGMethodHandler.class.getName(), false, mockLoader);
Object powerMockTestNGMethodHandlerInstance = powerMockTestNGMethodHandlerClass.getConstructor(Class.class)
.newInstance(
testInstance.getClass());
Whitebox.invokeMethod(testInstance, "setHandler", powerMockTestNGMethodHandlerInstance);
}
private boolean extendsPowerMockTestCase(Class> actualTestClass) {
return PowerMockTestCase.class.isAssignableFrom(actualTestClass);
}
}