Package org.ops4j.pax.exam.invoker.junit.internal

Source Code of org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker

/*
* Copyright 2011 Harald Wellmann
*
* 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.ops4j.pax.exam.invoker.junit.internal;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Method;
import java.util.List;

import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Request;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.ops4j.pax.exam.ProbeInvoker;
import org.ops4j.pax.exam.TestContainerException;
import org.ops4j.pax.exam.WrappedTestContainerException;
import org.ops4j.pax.exam.util.Injector;
import org.osgi.framework.BundleContext;

/**
* A ProbeInvoker which delegates the test method invocation to JUnit.
* <p>
* By doing so, JUnit can handle {@code @Before}, {@code @After} and {@code @Rule} annotations in
* the usual way.
* <p>
* The test method to be executed is defined by an encoded instruction from
* {@code org.ops4j.pax.exam.spi.intern.DefaultTestAddress}.
*
* @author Harald Wellmann
* @since 2.3.0, August 2011
*/
public class JUnitProbeInvoker implements ProbeInvoker {

    private BundleContext ctx;
    private String clazz;
    private String method;
    private Injector injector;

    private Class<?> testClass;

    public JUnitProbeInvoker(String encodedInstruction, BundleContext bundleContext, Injector injector) {
        // parse class and method out of expression:
        String[] parts = encodedInstruction.split(";");
        clazz = parts[0];
        method = parts[1];
        ctx = bundleContext;
        this.injector = injector;
        try {
            testClass = ctx.getBundle().loadClass(clazz);
        }
        catch (ClassNotFoundException e) {
            throw new TestContainerException(e);
        }
    }

    public void call(Object... args) {
        if (!(findAndInvoke(args))) {
            throw new TestContainerException(" Test " + method + " not found in test class "
                + testClass.getName());
        }
    }

    private boolean findAndInvoke(Object...args) {
        Integer index = null;
        try {
            /*
             * If args are present, we expect exactly one integer argument, defining the index of
             * the parameter set for a parameterized test.
             */
            if (args.length > 0) {
                if (!(args[0] instanceof Integer)) {
                    throw new TestContainerException("Integer argument expected");
                }
                index = (Integer) args[0];
            }

            // find matching method
            for (Method m : testClass.getMethods()) {
                if (m.getName().equals(method)) {
                    // we assume its correct:
                    invokeViaJUnit(m, index);
                    return true;
                }
            }
        }
        catch (NoClassDefFoundError e) {
            throw new TestContainerException(e);
        }
        return false;
    }

    /**
     * Invokes a given method of a given test class via {@link JUnitCore} and injects dependencies
     * into the instantiated test class.
     * <p>
     * This requires building a {@code Request} which is aware of an {@code Injector} and a
     * {@code BundleContext}.
     *
     * @param testClass
     * @param testMethod
     * @throws TestContainerException
     */
    private void invokeViaJUnit(final Method testMethod, Integer index) {
        Request classRequest = new ContainerTestRunnerClassRequest(testClass, injector, index);
        Description methodDescription = Description.createTestDescription(testClass, method);
        Request request = classRequest.filterWith(methodDescription);
        JUnitCore junit = new JUnitCore();
        Result result = junit.run(request);
        List<Failure> failures = result.getFailures();
        if (!failures.isEmpty()) {
            throw createTestContainerException(failures.toString(), failures.get(0).getException());
        }
    }
   
    /**
     * Creates exception for test failure and makes sure it is serializable.
     * @param message
     * @param ex
     * @return serializable exception
     */
    private TestContainerException createTestContainerException(String message, Throwable ex) {
        return isSerializable(ex)
            ? new TestContainerException(message, ex)
            : new WrappedTestContainerException(message, ex);
    }

    /**
     * Check if given exception is serializable by doing a serialization and
     * checking the exception
     *
     * @param ex exception to check
     * @return if the given exception is serializable
     */
    private boolean isSerializable(Throwable ex) {
        try {
            new ObjectOutputStream(new ByteArrayOutputStream()).writeObject(ex);
            return true;
        }
        // CHECKSTYLE:SKIP
        catch (Throwable ex2) {
            return false;
        }
    }
}
TOP

Related Classes of org.ops4j.pax.exam.invoker.junit.internal.JUnitProbeInvoker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.