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

patterntesting.runtime.junit.SmokeRunner Maven / Gradle / Ivy

/*
 * $Id: SmokeRunner.java,v 1.44 2016/12/18 20:19:38 oboehm Exp $
 *
 * Copyright (c) 2010 by Oliver Boehm
 *
 * 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 orimplied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * (c)reated 29.03.2010 by oliver ([email protected])
 */

package patterntesting.runtime.junit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.*;
import org.junit.*;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.MultipleFailureException;
import org.junit.internal.runners.statements.RunAfters;
import org.junit.internal.runners.statements.RunBefores;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.*;

import patterntesting.runtime.annotation.RunTestOn;
import patterntesting.runtime.annotation.SkipTestOn;
import patterntesting.runtime.junit.internal.ProfiledStatement;
import patterntesting.runtime.junit.internal.SmokeFilter;

/**
 * This is the eXtended Runner for JUnit 4 which handles the SmokeTest and other
 * annotations. In previous (intermediate) version it was called "XRunner". But
 * because this may be a little bit confusing name it was renamed to
 * "SmokeRunner" for the final version.
 * 

* It can be used together with the {@code @RunWith} annotation of JUnit 4. *

* * @author oliver * @since 1.0 (29.03.2010) */ @SuppressWarnings("deprecation") public class SmokeRunner extends ParentRunner { private static final Logger LOG = LogManager.getLogger(SmokeRunner.class); private final SmokeFilter xfilter = new SmokeFilter(); /** * Creates a SmokeRunner to run klass methods. * * @param klass * the test class to run * @throws InitializationError * if the test class is malformed */ public SmokeRunner(final Class klass) throws InitializationError { super(klass); } /** * The ParentRunner allows us no access to the filter. So we added this * method here (e.g. needed by the ParallelRunner). * * @return the SmokeFilter */ protected final SmokeFilter getFilter() { return this.xfilter; } /** * Returns the methods that run tests. Default implementation returns all * methods annotated with {@code @Test} on this class and superclasses that * are not overridden. *

* Since 1.5 there was a hide flag for the {@link RunTestOn} and * {@link SkipTestOn} introduced where the unit test should not be appear in * the list of the ignored tests if it will not be executed. So we filter * out these tests here. *

* * @return the methods that run tests */ @Override protected List getChildren() { Description suiteDescription = Description.createSuiteDescription(getName(), getRunnerAnnotations()); if (xfilter.shouldBeHidden(suiteDescription)) { Collection annotations = suiteDescription.getAnnotations(); for (Annotation a : annotations) { if (a.toString().contains("hide=true")) { throw new UnsupportedOperationException("@" + a.annotationType().getSimpleName() + "(hide=true) is only supported in method annotations of " + suiteDescription); } } throw new UnsupportedOperationException( "flag 'hide=true' is only supported in method annotations of " + suiteDescription); } List testMethods = getTestMethods(); return filtered(testMethods); } private List filtered(final List testMethods) { List nonHiddenMethods = new ArrayList<>(); for (FrameworkMethod method : testMethods) { if (xfilter.shouldBeHidden(describeChild(method))) { LOG.trace("{} is hidden.", method); } else { nonHiddenMethods.add(method); } } return nonHiddenMethods; } /** * Gets the test methods. This method can be overriden by subclasses (like * the ProxyRunner) which also want to filter out test methods with * "hide=true". * * @return the test methods */ protected List getTestMethods() { TestClass testClass = this.getTestClass(); Class javaClass = testClass.getJavaClass(); if (ProfiledStatement.isTestCaseClass(testClass)) { return getJUnit3TestMethods(javaClass); } return testClass.getAnnotatedMethods(Test.class); } /** * Create a Description of a single test named * name in the class clazz. Generally, this will * be a leaf Description. (see also * {@link BlockJUnit4ClassRunner}) * * @param child * the name of the test (a method name for test annotated with * {@link org.junit.Test}) * @return the description * @see org.junit.runners.ParentRunner#describeChild(java.lang.Object) */ @Override protected Description describeChild(final FrameworkMethod child) { return Description.createTestDescription(getTestClass().getJavaClass(), child.getName(), child.getAnnotations()); } /** * Checks the annotation of the method marked as "@BeforeClass" and add (or * filters out) the beforeClass method (needed to solve. * * @param statement * the statement(s) before * @return the statement(s) after with the BeforeClass method * @see org.junit.runners.ParentRunner#withBeforeClasses(org.junit.runners.model.Statement) */ @Override protected Statement withBeforeClasses(final Statement statement) { List filtered = filter(BeforeClass.class); if (filtered.isEmpty()) { return statement; } return new RunBefores(statement, filtered, null); } /** * Checks the annotation of the method marked as "@AfterClass" and add (or * filters out) the afterClass method (needed to solve. * * @param statement * the statement(s) before * @return the statement(s) after with the AfterClass method */ @Override protected Statement withAfterClasses(final Statement statement) { List filtered = filter(AfterClass.class); if (filtered.isEmpty()) { return statement; } return new RunAfters(statement, filtered, null); } private List filter(final Class annotationClass) { List methods = this.getTestClass().getAnnotatedMethods(annotationClass); return filter(methods); } private List filter(final List methods) { List filtered = new ArrayList<>(); for (FrameworkMethod fm : methods) { if (!this.xfilter.shouldBeIgnored(describeChild(fm))) { filtered.add(fm); } else if (LOG.isTraceEnabled()) { LOG.trace(fm.getMethod() + " is filtered out"); } } return filtered; } /** * Runs the test corresponding to {@code child}, which can be assumed to be * an element of the list returned by {@link ParentRunner#getChildren()}. * Subclasses are responsible for making sure that relevant test events are * reported through {@code notifier} * * @param method * the method * @param notifier * the notifier */ @Override @SuppressWarnings("all") protected void runChild(final FrameworkMethod method, final RunNotifier notifier) { Description description = describeChild(method); try { if (shouldBeIgnored(method)) { notifier.fireTestIgnored(description); return; } } catch (IllegalArgumentException iae) { notifier.fireTestStarted(description); fireTestAssumptionFailed(notifier, description, iae); notifier.fireTestFinished(description); return; } notifier.fireTestStarted(description); Statement stmt = methodBlock(method); try { stmt.evaluate(); } catch (AssumptionViolatedException ex) { fireTestAssumptionFailed(notifier, description, ex); } catch (Throwable e) { addFailure(notifier, e, description); } finally { logStatement(stmt); notifier.fireTestFinished(description); } } /** * In JUnit 4.5 and newer we can use the fireTestAssumptionFailed(..) of the * {@link RunNotifier} class. But JUnit 4.4 does not provide this method. *

* We could map it to the {@link RunNotifier#fireTestFailure(Failure)} * method - but this does not work for JUnit 4.5 (some internal JUnit tests * will fail if you try that). We could compile with JUnit 4.5, run the * tests with JUnit 4.4 and see what will happen. Perhaps we can catch the * exception and call the {@link RunNotifier#fireTestFailure(Failure)} * method. We could also give up because the architecture of JUnit has * changed too much between 4.4 and 4.5 - this is, what we do now. *

* * @param notifier * the notifier * @param description * the description * @param ex * the ex * @since 1.2.20 */ protected static void fireTestAssumptionFailed(final RunNotifier notifier, final Description description, final Exception ex) { notifier.fireTestAssumptionFailed(new Failure(description, ex)); } /** * We will give a subclass (like e.g. ParallelRunner) the chance to report * the statement with its own logger. * * @param stmt * the stmt to be logged */ protected void logStatement(final Statement stmt) { LOG.info("{}", stmt); } /** * Here we handle annotations like {@code @Ignore} where the execution of * the test method should be ignored. * * @param method * the test method * @return true or false */ protected final boolean shouldBeIgnored(final FrameworkMethod method) { Ignore ignore = method.getAnnotation(Ignore.class); if (ignore != null) { if (LOG.isDebugEnabled()) { String reason = ignore.value(); if (StringUtils.isNotEmpty(reason)) { reason = " (" + reason + ")"; } LOG.debug(this.getTestClass().getName() + "." + method.getName() + " ignored" + reason); } return true; } return this.xfilter.shouldBeIgnored(describeChild(method)); } /** * Should be run. * * @param method * the method * @return true, if successful */ protected final boolean shouldBeRun(final FrameworkMethod method) { return !this.xfilter.shouldBeIgnored(describeChild(method)); } /** * This method was inspired from an internal JUnit class * (EachTestNotifier#addFailure(Throwable)). * * @param notifier * the notifier * @param targetException * the target exception * @param description * the description */ protected final void addFailure(final RunNotifier notifier, final Throwable targetException, final Description description) { if (targetException instanceof MultipleFailureException) { MultipleFailureException mfe = (MultipleFailureException) targetException; for (Throwable each : mfe.getFailures()) { addFailure(notifier, each, description); } return; } notifier.fireTestFailure(new Failure(description, targetException)); } /** * Creates a RunStatement for the given test method. * * @param method * the test method * @return a created RunStatement */ protected Statement methodBlock(final FrameworkMethod method) { return new ProfiledStatement(this.getTestClass(), method); } /** * Here we look after public void methods with "test" as prefix and with no * arguments. *

* NOTE: This method is public because it is also needed by * patterntesting.concurrent.junit.JUnit3Executor *

* * @param testClass * the test class * @return a list of public methods starting with prefix "test" */ public static List getJUnit3TestMethods(final Class testClass) { List children = new ArrayList<>(); Method[] methods = testClass.getDeclaredMethods(); for (int i = 0; i < methods.length; i++) { Method method = methods[i]; if (isTestMethod(method)) { FrameworkMethod child = new FrameworkMethod(method); children.add(child); } } return children; } private static boolean isTestMethod(Method method) { int mod = method.getModifiers(); if ((method.getParameterTypes().length > 0) || Modifier.isStatic(mod)) { return false; } Class returnType = method.getReturnType(); if (!"void".equalsIgnoreCase(returnType.toString())) { return false; } if (method.getName().startsWith("test")) { if (Modifier.isPublic(mod)) { return true; } LOG.warn(method + " isn't public"); } return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy