All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.powermock.modules.testng.internal.PowerMockClassloaderObjectFactory Maven / Gradle / Ivy

There is a newer version: 2.0.9
Show newest version
/*
 * Copyright 2011 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.core.MockRepository;
import org.powermock.core.classloader.MockClassLoader;
import org.powermock.core.transformers.MockTransformer;
import org.powermock.core.transformers.impl.MainMockTransformer;
import org.powermock.modules.testng.PowerMockTestCase;
import org.powermock.reflect.Whitebox;
import org.powermock.reflect.proxyframework.RegisterProxyFramework;
import org.powermock.tests.utils.IgnorePackagesExtractor;
import org.powermock.tests.utils.TestClassesExtractor;
import org.powermock.tests.utils.impl.MockPolicyInitializerImpl;
import org.powermock.tests.utils.impl.PowerMockIgnorePackagesExtractorImpl;
import org.powermock.tests.utils.impl.PrepareForTestExtractorImpl;
import org.testng.IObjectFactory;

import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

@SuppressWarnings("serial")
public class PowerMockClassloaderObjectFactory implements IObjectFactory {

	private final MockClassLoader mockLoader;

	private final TestClassesExtractor testClassesExtractor;

	private final IgnorePackagesExtractor ignorePackagesExtractor;

        private final ExpectedExceptionsExtractor expectedExceptionsExtractor;

	public PowerMockClassloaderObjectFactory() {
		List mockTransformerChain = new ArrayList();
		final MainMockTransformer mainMockTransformer = new MainMockTransformer();
		mockTransformerChain.add(mainMockTransformer);

		String[] classesToLoadByMockClassloader = new String[0];
		String[] packagesToIgnore = new String[0];
		mockLoader = new MockClassLoader(classesToLoadByMockClassloader, packagesToIgnore);
		mockLoader.setMockTransformerChain(mockTransformerChain);
		testClassesExtractor = new PrepareForTestExtractorImpl();
		ignorePackagesExtractor = new PowerMockIgnorePackagesExtractorImpl();
                expectedExceptionsExtractor = new PowerMockExpectedExceptionsExtractorImpl();
	}

	public Object newInstance(@SuppressWarnings("rawtypes") Constructor constructor, Object... params) {
		/*
		 * For extra safety clear the MockitoRepository on each new
		 * instantiation of the object factory. This is good in cases where a
		 * previous test has used e.g. PowerMock#createMock(..) to create a mock
		 * without using this factory. That means that there's some state left in
		 * the MockRepository that hasn't been cleared. Currently clearing the
		 * MockRepository from any classloader will clear the previous state but
		 * it's not certain that this is always the case.
		 */
		MockRepository.clear();
		Class testClass = constructor.getDeclaringClass();
		mockLoader.addIgnorePackage(ignorePackagesExtractor.getPackagesToIgnore(testClass));
                mockLoader.addIgnorePackage(expectedExceptionsExtractor.getPackagesToIgnore(testClass));
		mockLoader.addClassesToModify(testClassesExtractor.getTestClasses(testClass));
		try {
			registerProxyframework(mockLoader);
			new MockPolicyInitializerImpl(testClass).initialize(mockLoader);
			final Class testClassLoadedByMockedClassLoader = createTestClass(testClass);
			Constructor con = testClassLoadedByMockedClassLoader.getConstructor(constructor.getParameterTypes());
			final Object testInstance = con.newInstance(params);
			if (!extendsPowerMockTestCase(testClass)) {
				setInvocationHandler(testInstance);
			}
			return testInstance;
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	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);
	}

	/**
	 * 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 {

			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);
			Class c = Whitebox.invokeMethod(f, "createClass");
			return c;
		}
	}

	private boolean extendsPowerMockTestCase(Class actualTestClass) {
		return PowerMockTestCase.class.isAssignableFrom(actualTestClass);
	}

	private void registerProxyframework(ClassLoader classLoader) {
		Class proxyFrameworkClass = null;
		try {
			proxyFrameworkClass = Class.forName("org.powermock.api.extension.proxyframework.ProxyFrameworkImpl", false, classLoader);
		} catch (ClassNotFoundException e) {
			throw new IllegalStateException(
					"Extension API internal error: org.powermock.api.extension.proxyframework.ProxyFrameworkImpl could not be located in classpath.");
		}

		Class proxyFrameworkRegistrar = null;
		try {
			proxyFrameworkRegistrar = Class.forName(RegisterProxyFramework.class.getName(), false, classLoader);
		} catch (ClassNotFoundException e) {
			// Should never happen
			throw new RuntimeException(e);
		}
		try {
			Whitebox.invokeMethod(proxyFrameworkRegistrar, "registerProxyFramework", Whitebox.newInstance(proxyFrameworkClass));
		} catch (RuntimeException e) {
			throw e;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy