Package com.btmatthews.selenium.junit4.runner

Source Code of com.btmatthews.selenium.junit4.runner.SeleniumJUnit4ClassRunner$SeleniumWebDriverJUnit4ClassRunner

/*
* Copyright 2011-2013 Brian Thomas Matthews
*
* 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 com.btmatthews.selenium.junit4.runner;

import com.thoughtworks.selenium.Selenium;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.junit.rules.TestRule;
import org.junit.runner.Runner;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkField;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.TestClass;
import org.openqa.selenium.WebDriver;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

/**
* A test runner that runs a test case as a suite of tests.
*
* @author <a href="mailto:brian@btmatthews.com">Brian Thomas Matthews</a>
* @since 1.0.0
*/
public class SeleniumJUnit4ClassRunner extends Suite {

    /**
     * Creates a {@code SeleniumJUnit4ClassRunner} to run the test cases
     * encapsulated within {@code klass}.
     *
     * @param klass The class that encapsulates the test cases.
     * @throws InitializationError If there was an error initialising the test runner.
     */
    public SeleniumJUnit4ClassRunner(final Class<?> klass)
            throws InitializationError {
        super(klass, buildRunners(klass));
    }

    /**
     * Build the test runners for each browser. The test class must have been
     * annotated with {@link ServerConfiguration} or
     * {@link WebDriverConfiguration} to provide the configuration.
     *
     * @param klass The test class.
     * @return A list of {@link Runner} objects.
     * @throws InitializationError If there was an error initialising the test runners.
     */
    private static List<Runner> buildRunners(final Class<?> klass)
            throws InitializationError {
        final List<Runner> runners;
        final ServerConfiguration seleniumServerConfiguration = klass
                .getAnnotation(ServerConfiguration.class);
        final WebDriverConfiguration webDriverConfiguration = klass
                .getAnnotation(WebDriverConfiguration.class);
        final WrappedDriverConfiguration wrappedDriverConfiguration = klass
                .getAnnotation(WrappedDriverConfiguration.class);
        if (seleniumServerConfiguration != null) {
            runners = buildSeleniumServerRunners(seleniumServerConfiguration,
                    klass);
        } else if (webDriverConfiguration != null) {
            runners = buildWebDriverRunners(webDriverConfiguration, klass);
        } else if (wrappedDriverConfiguration != null) {
            runners = buildWrappedDriverRunners(wrappedDriverConfiguration,
                    klass);
        } else {
            throw new InitializationError(
                    "Annotate test class with either ServerConfiguration, WebDriverConfiguration or WrappedDriverConfiguration");
        }
        return runners;
    }

    /**
     * Build the test runners for each browser for test cases that were
     * annotated with {@link WebDriverConfiguration} to provide the
     * configuration. A test runner is created for each web driver specified by
     * {@link WebDriverConfiguration#baseDrivers()}.
     *
     * @param configuration The {@link WebDriverConfiguration} annotation.
     * @param klass         The test class.
     * @return A list of {@link Runner} test runners.
     * @throws InitializationError If there was an error initialising the test runners.
     */
    private static List<Runner> buildWebDriverRunners(
            final WebDriverConfiguration configuration, final Class<?> klass)
            throws InitializationError {
        final List<Runner> runners = new ArrayList<Runner>();
        try {
            for (final Class<? extends WebDriver> webDriverClass : configuration
                    .baseDrivers()) {
                final WebDriverFactory factory = new WebDriverFactory(webDriverClass);
                runners.add(new SeleniumWebDriverJUnit4ClassRunner(factory,
                        klass));
            }
        } catch (final Exception e) {
            throw new InitializationError(e);
        }
        return runners;
    }

    /**
     * Build the test runners for each browser for test cases that were
     * annotated with {@link WrappedDriverConfiguration} to provide the
     * configuration. A test runner is created for each web driver specified by
     * {@link WrappedDriverConfiguration#baseDrivers()}.
     *
     * @param configuration The {@link WrappedDriverConfiguration} annotation.
     * @param klass         The test class.
     * @return A list of {@link Runner} test runners.
     * @throws InitializationError If there was an error initialising the test runners.
     */
    private static List<Runner> buildWrappedDriverRunners(
            final WrappedDriverConfiguration configuration, final Class<?> klass)
            throws InitializationError {
        final List<Runner> runners = new ArrayList<Runner>();
        try {
            for (final Class<? extends WebDriver> webDriverClass : configuration
                    .baseDrivers()) {
                final WrappedDriverFactory factory = new WrappedDriverFactory(
                        configuration, webDriverClass);
                runners.add(new SeleniumServerJUnit4ClassRunner(factory, klass));
            }
        } catch (final Exception e) {
            throw new InitializationError(e);
        }
        return runners;
    }

    /**
     * Build the test runners for each browser for test cases that were
     * annotated with {@link ServerConfiguration} to provide the configuration.
     * A test runner is created for each browser start command specified by
     * {@link ServerConfiguration#browserStartCommands()}.
     *
     * @param configuration The {@link ServerConfiguration} annotation.
     * @param klass         The test class.
     * @return A list of {@link Runner} test runners.
     * @throws InitializationError If there was an error initialising the test runners.
     */
    private static List<Runner> buildSeleniumServerRunners(
            final ServerConfiguration configuration, final Class<?> klass)
            throws InitializationError {
        final List<Runner> runners = new ArrayList<Runner>();
        try {
            for (final String browserStartCommand : configuration
                    .browserStartCommands()) {
                final ServerFactory factory = new ServerFactory(configuration,
                        browserStartCommand);
                runners.add(new SeleniumServerJUnit4ClassRunner(factory, klass));
            }
        } catch (final Exception e) {
            throw new InitializationError(e);
        }
        return runners;
    }

    /**
     * An abstract test runner that implements the
     * {@link Runner#run(RunNotifier)} and {@link org.junit.runners.ParentRunner<T>#createTest() ParentRunner<T>#createTest()}
     * methods generically.
     *
     * @param <T> <ul>
     *            <li>{@link Selenium} for tests that use the Selenium 1.0 API</li>
     *            <li>{@link WebDriver} for tests that use the Selenium 2.0 API</li>
     *            </ul>
     * @param <A> <ul>
     *            <li>{@link SeleniumServer} for tests that use the Selenium 1.0
     *            API</li>
     *            <li>{@link SeleniumWebDriver} for tests that use the Selenium
     *            2.0 API</li>
     *            </ul>
     */
    abstract static class AbstractSeleniumJUnit4ClassRunner<T, A extends Annotation>
            extends BlockJUnit4ClassRunner {

        /**
         * The Selenium object.
         */
        private T selenium;

        /**
         * The factory used to create, start and stop the Selenium object.
         */
        private SeleniumFactory<T> seleniumFactory;

        /**
         * The annotation type which will be used to identified fields in test
         * objects and rules that are to be injected with the Selenium server or
         * web driver.
         */
        private Class<A> annotationType;

        /**
         * Construct a test runner that will run the tests for a specific
         * browser instance using a Selenium server or web driver..
         *
         * @param factory The factory used to create, start and stop the Selenium
         *                server or web driver.
         * @param type    The annotation type which will be used to identified
         *                fields in test objects and rules that are to be injected
         *                with the Selenium server or web driver.
         * @param klass   The test class.
         * @throws InitializationError If there was a problem constructing the test runner.
         */
        public AbstractSeleniumJUnit4ClassRunner(
                final SeleniumFactory<T> factory, final Class<A> type,
                final Class<?> klass) throws InitializationError {
            super(klass);
            seleniumFactory = factory;
            annotationType = type;
        }

        @Override
        public void run(final RunNotifier notifier) {
            try {
                selenium = seleniumFactory.create();
                seleniumFactory.start(selenium);
                try {
                    super.run(notifier);
                } finally {
                    seleniumFactory.stop(selenium);
                }
            } catch (Throwable e) {
                final Failure failure = new Failure(getDescription(), e);
                notifier.fireTestFailure(failure);
            } finally {
                selenium = null;
            }
        }

        /**
         * Create the test object and inject Selenium server or web driver into
         * fields that were annotated with {@code annotationType}.
         *
         * @return The test object.
         * @throws Exception If there was an error creating the test object.
         */
        @Override
        protected Object createTest() throws Exception {
            final Object test = super.createTest();
            final TestClass testClass = getTestClass();
            final String browser = seleniumFactory.getBrowser();

            List<FrameworkField> fields = testClass
                    .getAnnotatedFields(annotationType);
            for (final FrameworkField field : fields) {
                FieldUtils.writeField(field.getField(), test, selenium, true);
            }

            fields = testClass.getAnnotatedFields(SeleniumBrowser.class);
            for (final FrameworkField field : fields) {
                FieldUtils.writeField(field.getField(), test, browser, true);
            }

            final List<TestRule> rules = this.getTestRules(test);
            for (final TestRule rule : rules) {
                final Field[] ruleFields = rule.getClass().getDeclaredFields();
                for (final Field ruleField : ruleFields) {
                    if (ruleField.getAnnotation(annotationType) != null) {
                        FieldUtils.writeField(ruleField, rule, selenium, true);
                    } else if (ruleField.getAnnotation(SeleniumBrowser.class) != null) {
                        FieldUtils.writeField(ruleField, rule, browser, true);
                    }
                }
            }
            return test;
        }
    }

    /**
     * A test runner that will run tests for a specific browser instance using
     * the Selenium server interface. This Selenium server may actually be
     * wrapping a web driver.
     */
    static class SeleniumServerJUnit4ClassRunner extends
            AbstractSeleniumJUnit4ClassRunner<Selenium, SeleniumServer> {

        /**
         * Construct a test runner that will run the tests for a specific
         * browser instance using a Selenium server. The Selenium server may be
         * wrapping a web driver.
         *
         * @param factory The factory used to create, start and stop the Selenium
         *                server.
         * @param klass   The test class.
         * @throws InitializationError If there was a problem constructing the test runner.
         */
        public SeleniumServerJUnit4ClassRunner(
                final SeleniumFactory<Selenium> factory, final Class<?> klass)
                throws InitializationError {
            super(factory, SeleniumServer.class, klass);
        }
    }

    /**
     * A test runner that will run the tests for a specific browser instance
     * using a Selenium web driver.
     */
    static class SeleniumWebDriverJUnit4ClassRunner extends
            AbstractSeleniumJUnit4ClassRunner<WebDriver, SeleniumWebDriver> {

        /**
         * Construct a test runner that will run the tests for a specific
         * browser instance using a Selenium web driver.
         *
         * @param factory The factory used to create, start and stop the Selenium
         *                web driver.
         * @param klass   The test class.
         * @throws InitializationError If there was a problem constructing the test runner.
         */
        public SeleniumWebDriverJUnit4ClassRunner(
                final WebDriverFactory factory, final Class<?> klass)
                throws InitializationError {
            super(factory, SeleniumWebDriver.class, klass);
        }
    }
}
TOP

Related Classes of com.btmatthews.selenium.junit4.runner.SeleniumJUnit4ClassRunner$SeleniumWebDriverJUnit4ClassRunner

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.