/** * Copyright 2006 Jukka Zitting * * 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. */ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.regex.Pattern; import junit.framework.TestCase; /** * Test case that can be exluded from a test run using system properties. * This is especially useful for known issues or similar test cases that * are expected to fail, but should not flag the entire test run as a * failure. *

* This class overrides the {@link #runBare()} method to check whether * the test should or should not be run. This decision is based on the * junit.excludes and junit.includes system * properties. If defined, these properties are interpreted as * whitespace-separated sets of test identifiers to exclude * or include. Normally each test is included in the test run, but identifying * a test in junit.excludes will exclude that test. The exclusion * can be overridden by identifying the test in junit.includes * which again overrides the exclusion. *

* Each test is identified by a set of test identifiers. The default * identifiers of a test are: *

*

* The set of identifiers of a test can be extended using the * {@link #addIdentifier(String)} method. A common use case for this * would be for example to include the issue tracker identifier for the * known issue for which the test case was written. */ public abstract class ExcludableTestCase extends TestCase { /** * Whitespace pattern for splitting the system property strings * to sets of test identifiers. */ private static final Pattern WHITESPACE = Pattern.compile("\\s+"); /** * The set of test identifiers to be excluded from the test run. */ private static final Collection EXCLUDES = new HashSet(Arrays.asList( WHITESPACE.split(System.getProperty("junit.excludes", "")))); /** * The set of test identifiers to be included in the test run even if * the test would otherwise be excluded. */ private static final Collection INCLUDES = new HashSet(Arrays.asList( WHITESPACE.split(System.getProperty("junit.includes", "")))); /** * Identifiers of this test. */ private final Collection identifiers = new ArrayList(); /** * Creates an excludable test case without a name. */ public ExcludableTestCase() { super(); } /** * Creates an excludable test case with the given name. * * @param name test name */ public ExcludableTestCase(final String name) { super(name); } /** * Adds an identifier to this test. * * @param identifier test identifier */ public final void addIdentifier(final String identifier) { identifiers.add(identifier); } //------------------------------------------------------------< TestCase > /** * Runs the bare test sequence unless the test has been excluded. * Determines the exclusion by comparing the set of test identifiers * to the contents of the junit.excludes and * junit.includes system properties. If the test is not * excluded, then the standard {@link TestCase#runBare()} method is * invoked. * * @throws Throwable if any exception is thrown by the test */ public final void runBare() throws Throwable { // Add default test identifiers String className = getClass().getName(); addIdentifier(className); String testName = getName(); if (testName != null) { addIdentifier(className + "#" + testName); addIdentifier(testName); } int dot = className.lastIndexOf('.'); if (dot >= 0) { String localName = className.substring(dot + 1); addIdentifier(localName); if (testName != null) { addIdentifier(localName + "#" + testName); } if (dot > 0) { addIdentifier(className.substring(0, dot)); } } // Check for inclusion boolean include = true; for (Iterator i = identifiers.iterator(); include && i.hasNext();) { include = !EXCLUDES.contains(i.next()); } for (Iterator i = identifiers.iterator(); !include && i.hasNext();) { include = INCLUDES.contains(i.next()); } if (include) { super.runBare(); } } }