UnitilsJUnit4TestClassRunner.java :  » Testing » unitils » org » unitils » Java Open Source

Java Open Source » Testing » unitils 
unitils » org » unitils » UnitilsJUnit4TestClassRunner.java
/*
 * Copyright 2006-2007,  Unitils.org
 *
 * 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.unitils;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.internal.runners.*;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.unitils.core.TestListener;
import org.unitils.core.Unitils;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Custom test runner that will Unitils-enable your test. This will make sure that the
 * core unitils test listener methods are invoked in the expected order. See {@link TestListener} for
 * more information on the listener invocation order.
 * <p/>
 * NOTE: if a test fails, the error is logged as debug logging. This is a temporary work-around for
 * a problem with IntelliJ JUnit-4 runner that reports a 'Wrong test finished' error when something went wrong
 * in the before. [IDEA-12498]
 *
 * @author Tim Ducheyne
 * @author Filip Neven
 */
public class UnitilsJUnit4TestClassRunner extends JUnit4ClassRunner {

    /* The logger instance for this class */
    private static Log logger = LogFactory.getLog(UnitilsJUnit4TestClassRunner.class);

    /* The main test listener, that hooks this test into unitils */
    private static TestListener testListener;

    /* True if beforeAll was succesfully called */
    private static boolean beforeAllCalled;


    /**
     * Creates a test runner that runs all test methods in the given class.
     *
     * @param testClass the class, not null
     * @throws InitializationError
     */
    public UnitilsJUnit4TestClassRunner(Class<?> testClass) throws InitializationError {
        super(testClass);

        if (testListener == null) {
            testListener = getUnitils().createTestListener();
            createShutdownHook();
        }
    }


    @Override
    public void run(final RunNotifier notifier) {
        // if this is the first test, call beforeAll
        if (!beforeAllCalled) {
            try {
                testListener.beforeAll();
                beforeAllCalled = true;

            } catch (Throwable t) {
                logger.debug(getDescription(), t);
                notifier.testAborted(getDescription(), t);
                return;
            }
        }

        ClassRoadie classRoadie = new ClassRoadie(notifier, getTestClass(), getDescription(), new Runnable() {
            public void run() {
                runMethods(notifier);
            }
        });

        Throwable throwable = null;
        try {
            testListener.beforeTestClass(getTestClass().getJavaClass());
            classRoadie.runProtected();
        } catch (Throwable t) {
            notifier.fireTestFailure(new Failure(getDescription(), t));
            throwable = t;
        }
        try {
            testListener.afterTestClass(getTestClass().getJavaClass());
        } catch (Throwable t) {
            // first exception is typically the most meaningful, so ignore second exception
            if (throwable == null) {
                notifier.fireTestFailure(new Failure(getDescription(), t));
            }
        }
    }


    /**
     * Overriden JUnit4 method to be able to create a CustomMethodRoadie that will invoke the
     * unitils test listener methods at the apropriate moments.
     */
    protected void invokeTestMethod(Method method, RunNotifier notifier) {
        Description description = methodDescription(method);
        Object testObject;
        try {
            testObject = createTest();
        } catch (InvocationTargetException e) {
            notifier.testAborted(description, e.getCause());
            return;
        } catch (Exception e) {
            notifier.testAborted(description, e);
            return;
        }
        TestMethod testMethod = wrapMethod(method);
        new CustomMethodRoadie(testObject, method, testMethod, notifier, description).run();
    }


    /**
     * Custom method roadie that invokes the unitils test listener methods at the apropriate moments.
     */
    public static class CustomMethodRoadie extends MethodRoadie {


        /* Instance under test */
        protected Object testObject;

        /* Method under test */
        protected Method testMethod;


        /**
         * Creates a method roadie.
         *
         * @param testObject      The test instance, not null
         * @param testMethod      The test method, not null
         * @param jUnitTestMethod The JUnit test method
         * @param notifier        The run listener, not null
         * @param description     A test description
         */
        public CustomMethodRoadie(Object testObject, Method testMethod, TestMethod jUnitTestMethod, RunNotifier notifier, Description description) {
            super(testObject, jUnitTestMethod, notifier, description);
            this.testObject = testObject;
            this.testMethod = testMethod;
        }


        /**
         * Overriden JUnit4 method to be able to call {@link TestListener#afterTestTearDown}.
         */
        @Override
        public void runBeforesThenTestThenAfters(Runnable test) {
            Throwable throwable = null;
            try {
                testListener.beforeTestSetUp(testObject);
                super.runBeforesThenTestThenAfters(test);
            } catch (Throwable t) {
                addFailure(t);
                throwable = t;
            }
            try {
                testListener.afterTestTearDown(testObject);
            } catch (Throwable t) {
                // first exception is typically the most meaningful, so ignore second exception
                if (throwable == null) {
                    addFailure(t);
                }
            }
        }


        protected void runTestMethod() {
            Throwable throwable = null;
            try {
                testListener.beforeTestMethod(testObject, testMethod);
                super.runTestMethod();
            } catch (Throwable t) {
                addFailure(t);
                throwable = t;
            }
            try {
                testListener.afterTestMethod(testObject, testMethod, throwable);
            } catch (Throwable t) {
                // first exception is typically the most meaningful, so ignore second exception
                if (throwable == null) {
                    addFailure(t);
                }
            }
        }
    }


    /**
     * This will return the default singleton instance by calling {@link Unitils#getInstance()}.
     * <p/>
     * You can override this method to let it create and set your own singleton instance. For example, you
     * can let it create an instance of your own Unitils subclass and set it by using {@link Unitils#setInstance}.
     *
     * @return the unitils core instance, not null
     */
    protected Unitils getUnitils() {
        return Unitils.getInstance();
    }


    /**
     * Creates a hook that will call {@link TestListener#afterAll} during the shutdown of the VM.
     * <p/>
     * This seems te be the only way in JUnit4 to this, since there is no way to
     * able to know when all tests have run.
     */
    protected void createShutdownHook() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                if (testListener != null) {
                    testListener.afterAll();
                }
            }
        });
    }
}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.