git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@1452674 13f79535-47bb-0310-9956-ffa450edef68master
| @@ -234,6 +234,7 @@ Matthew Inger | |||||
| Matthew Kuperus Heun | Matthew Kuperus Heun | ||||
| Matthew Watson | Matthew Watson | ||||
| Michael Bayne | Michael Bayne | ||||
| Michael Clarke | |||||
| Michael Davey | Michael Davey | ||||
| Michael J. Sikorsky | Michael J. Sikorsky | ||||
| Michael McCallum | Michael McCallum | ||||
| @@ -87,6 +87,9 @@ Fixed bugs: | |||||
| set to ANSI_X3.4-1968. | set to ANSI_X3.4-1968. | ||||
| Bugzilla Report 54606 | Bugzilla Report 54606 | ||||
| * JUnit4 tests marked @Ignore do not appear in XML output | |||||
| Bugzilla Report 43969 | |||||
| Other changes: | Other changes: | ||||
| -------------- | -------------- | ||||
| @@ -957,6 +957,10 @@ | |||||
| <first>Michael</first> | <first>Michael</first> | ||||
| <last>Bayne</last> | <last>Bayne</last> | ||||
| </name> | </name> | ||||
| <name> | |||||
| <first>Michael</first> | |||||
| <last>Clarke</last> | |||||
| </name> | |||||
| <name> | <name> | ||||
| <first>Michael</first> | <first>Michael</first> | ||||
| <last>Davey</last> | <last>Davey</last> | ||||
| @@ -45,7 +45,7 @@ jasper-compiler.version=4.1.36 | |||||
| jasper-runtime.version=${jasper-compiler.version} | jasper-runtime.version=${jasper-compiler.version} | ||||
| jdepend.version=2.9.1 | jdepend.version=2.9.1 | ||||
| jruby.version=0.9.8 | jruby.version=0.9.8 | ||||
| junit.version=4.8.1 | |||||
| junit.version=4.11 | |||||
| jsch.version=0.1.42 | jsch.version=0.1.42 | ||||
| jython.version=2.1 | jython.version=2.1 | ||||
| #log4j 1.2.15 requires JMS and a few other Sun jars that are not in the m2 repo | #log4j 1.2.15 requires JMS and a few other Sun jars that are not in the m2 repo | ||||
| @@ -17,7 +17,7 @@ | |||||
| # this is a first attempt to document the build of the distribution | # this is a first attempt to document the build of the distribution | ||||
| # paths are hard-coded and obviously this is for a Cygwin/Windows combo | # paths are hard-coded and obviously this is for a Cygwin/Windows combo | ||||
| ####################################################################### | ####################################################################### | ||||
| rm -rf bootstrap build dist distribution | |||||
| rm -rf bootstrap build dist distribution java-repository | |||||
| unset ANT_HOME | unset ANT_HOME | ||||
| # OS specific support. $var _must_ be set to either true or false. | # OS specific support. $var _must_ be set to either true or false. | ||||
| cygwin=false; | cygwin=false; | ||||
| @@ -276,4 +276,49 @@ | |||||
| </junit> | </junit> | ||||
| </target> | </target> | ||||
| <!-- Junit4 Ignore and Assume for skipping tests --> | |||||
| <target name="testSkippableTests"> | |||||
| <mkdir dir="out"/> | |||||
| <junit fork="true"> | |||||
| <classpath refid="test"/> | |||||
| <formatter type="xml"/> | |||||
| <classpath refid="test"/> | |||||
| <batchtest todir="out"> | |||||
| <fileset dir="../../../../tests/junit"> | |||||
| <include | |||||
| name="org/example/junit/Junit4Skippable.java"/> | |||||
| <!-- tests remove out-dir on tearDown --> | |||||
| </fileset> | |||||
| </batchtest> | |||||
| </junit> | |||||
| </target> | |||||
| <target name="testTestMethods" > | |||||
| <echo file="${tmp.dir}/T1.java">public class T1 extends | |||||
| junit.framework.TestCase { | |||||
| public void testOK() {} | |||||
| public void testBad() {throw new RuntimeException("failed");} | |||||
| }</echo> | |||||
| <echo file="${tmp.dir}/T2.java"> | |||||
| import org.junit.Test; | |||||
| public class T2 { | |||||
| @Test | |||||
| public void ok() {} | |||||
| @Test | |||||
| public void bad() { | |||||
| throw new RuntimeException("failed");} | |||||
| }</echo> | |||||
| <javac srcdir="${tmp.dir}" destdir="${tmp.dir}" includes="T1.java,T2.java" source="5"> | |||||
| </javac> | |||||
| <junit fork="false" printsummary="true" haltonerror="true"> | |||||
| <classpath> | |||||
| <pathelement location="${tmp.dir}" /> | |||||
| <path refid="test" /> | |||||
| </classpath> | |||||
| <test name="T1" methods="testOK" /> | |||||
| <test name="T2" methods="ok" /> | |||||
| </junit> | |||||
| </target> | |||||
| </project> | </project> | ||||
| @@ -25,11 +25,13 @@ import java.io.StringWriter; | |||||
| import java.text.NumberFormat; | import java.text.NumberFormat; | ||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.JUnit4TestCaseFacade; | |||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.StringUtils; | import org.apache.tools.ant.util.StringUtils; | ||||
| import org.junit.Ignore; | |||||
| /** | /** | ||||
| * Prints plain text output of the test to a specified Writer. | * Prints plain text output of the test to a specified Writer. | ||||
| @@ -38,7 +40,7 @@ import org.apache.tools.ant.util.StringUtils; | |||||
| * @see FormatterElement | * @see FormatterElement | ||||
| * @see PlainJUnitResultFormatter | * @see PlainJUnitResultFormatter | ||||
| */ | */ | ||||
| public class BriefJUnitResultFormatter implements JUnitResultFormatter { | |||||
| public class BriefJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener { | |||||
| private static final double ONE_SECOND = 1000.0; | private static final double ONE_SECOND = 1000.0; | ||||
| @@ -141,6 +143,8 @@ public class BriefJUnitResultFormatter implements JUnitResultFormatter { | |||||
| sb.append(suite.failureCount()); | sb.append(suite.failureCount()); | ||||
| sb.append(", Errors: "); | sb.append(", Errors: "); | ||||
| sb.append(suite.errorCount()); | sb.append(suite.errorCount()); | ||||
| sb.append(", Skipped: "); | |||||
| sb.append(suite.skipCount()); | |||||
| sb.append(", Time elapsed: "); | sb.append(", Time elapsed: "); | ||||
| sb.append(numberFormat.format(suite.getRunTime() / ONE_SECOND)); | sb.append(numberFormat.format(suite.getRunTime() / ONE_SECOND)); | ||||
| sb.append(" sec"); | sb.append(" sec"); | ||||
| @@ -267,4 +271,42 @@ public class BriefJUnitResultFormatter implements JUnitResultFormatter { | |||||
| throw new BuildException(ex); | throw new BuildException(ex); | ||||
| } | } | ||||
| } | } | ||||
| @Override | |||||
| public void testIgnored(Test test) { | |||||
| String message = null; | |||||
| if (test instanceof JUnit4TestCaseFacade) { | |||||
| JUnit4TestCaseFacade facade = (JUnit4TestCaseFacade) test; | |||||
| Ignore annotation = facade.getDescription().getAnnotation(Ignore.class); | |||||
| if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { | |||||
| message = annotation.value(); | |||||
| } | |||||
| } | |||||
| formatSkip(test, message); | |||||
| } | |||||
| public void formatSkip(Test test, String message) { | |||||
| if (test != null) { | |||||
| endTest(test); | |||||
| } | |||||
| try { | |||||
| resultWriter.write(formatTest(test) + "SKIPPED"); | |||||
| if (message != null) { | |||||
| resultWriter.write(": "); | |||||
| resultWriter.write(message); | |||||
| } | |||||
| resultWriter.newLine(); | |||||
| } catch (IOException ex) { | |||||
| throw new BuildException(ex); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void testAssumptionFailure(Test test, Throwable cause) { | |||||
| formatSkip(test, cause.getMessage()); | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,89 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You 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.apache.tools.ant.taskdefs.optional.junit; | |||||
| import junit.framework.JUnit4TestAdapter; | |||||
| import junit.framework.JUnit4TestAdapterCache; | |||||
| import junit.framework.TestResult; | |||||
| import org.junit.runner.Description; | |||||
| import org.junit.runner.notification.Failure; | |||||
| import org.junit.runner.notification.RunListener; | |||||
| import org.junit.runner.notification.RunNotifier; | |||||
| /** | |||||
| * Provides a custom implementation of the notifier for a Junit4TestAdapter | |||||
| * so that skipped and ignored tests can be reported to the existing | |||||
| * <tt>TestListener</tt>s. | |||||
| * | |||||
| */ | |||||
| public class CustomJUnit4TestAdapterCache extends JUnit4TestAdapterCache { | |||||
| private static final CustomJUnit4TestAdapterCache INSTANCE = new CustomJUnit4TestAdapterCache(); | |||||
| public static CustomJUnit4TestAdapterCache getInstance() { | |||||
| return INSTANCE; | |||||
| } | |||||
| private CustomJUnit4TestAdapterCache() { | |||||
| super(); | |||||
| } | |||||
| public RunNotifier getNotifier(final TestResult result, final JUnit4TestAdapter adapter) { | |||||
| return getNotifier(result); | |||||
| } | |||||
| public RunNotifier getNotifier(final TestResult result) { | |||||
| final IgnoredTestResult resultWrapper = (IgnoredTestResult) result; | |||||
| RunNotifier notifier = new RunNotifier(); | |||||
| notifier.addListener(new RunListener() { | |||||
| @Override | |||||
| public void testFailure(Failure failure) throws Exception { | |||||
| result.addError(asTest(failure.getDescription()), failure.getException()); | |||||
| } | |||||
| @Override | |||||
| public void testFinished(Description description) throws Exception { | |||||
| result.endTest(asTest(description)); | |||||
| } | |||||
| @Override | |||||
| public void testStarted(Description description) throws Exception { | |||||
| result.startTest(asTest(description)); | |||||
| } | |||||
| @Override | |||||
| public void testIgnored(Description description) throws Exception { | |||||
| if (resultWrapper != null) { | |||||
| resultWrapper.testIgnored(asTest(description)); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void testAssumptionFailure(Failure failure) { | |||||
| if (resultWrapper != null) { | |||||
| resultWrapper.testAssumptionFailure(asTest(failure.getDescription()), failure.getException()); | |||||
| } | |||||
| } | |||||
| }); | |||||
| return notifier; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,53 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You 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.apache.tools.ant.taskdefs.optional.junit; | |||||
| import junit.framework.Test; | |||||
| import junit.framework.TestListener; | |||||
| import org.junit.runner.notification.Failure; | |||||
| /** | |||||
| * Provides the functionality for TestListeners to be able to be notified of | |||||
| * the necessary Junit4 events for test being ignored (@Ignore annotation) | |||||
| * or skipped (Assume failures). Tests written in Junit4 will report against | |||||
| * the methods in this interface alongside the methods in the existing TestListener | |||||
| */ | |||||
| public interface IgnoredTestListener extends TestListener { | |||||
| /** | |||||
| * Reports when a test has been marked with the @Ignore annotation. The parameter | |||||
| * should normally be typed to Junit's {@link junit.framework.JUnit4TestCaseFacade} | |||||
| * so implementing classes should be able to get the details of the ignore by casting | |||||
| * the argument and retrieving the descriptor from the test. | |||||
| * @param test | |||||
| */ | |||||
| void testIgnored(Test test); | |||||
| /** | |||||
| * Receive a report that a test has failed an assumption. Within JUnit4 | |||||
| * this is normally treated as a test being skipped, although how any | |||||
| * listener handles this is up to that specific listener.<br /> | |||||
| * <b>Note:</b> Tests that throw assumption failures will still report | |||||
| * the endTest method, which may differ from how the addError and addFailure | |||||
| * methods work, it's up for any implementing classes to handle this. | |||||
| * @param test the details of the test and failure that have triggered this report. | |||||
| * @param exception the AssumptionViolatedException thrown from the current assumption failure. | |||||
| */ | |||||
| void testAssumptionFailure(Test test, Throwable exception); | |||||
| } | |||||
| @@ -0,0 +1,99 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You 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.apache.tools.ant.taskdefs.optional.junit; | |||||
| import java.util.ArrayList; | |||||
| import java.util.List; | |||||
| import junit.framework.Test; | |||||
| import junit.framework.TestListener; | |||||
| import junit.framework.TestResult; | |||||
| /** | |||||
| * Records ignored and skipped tests reported as part of the execution of | |||||
| * JUnit 4 tests. | |||||
| * | |||||
| */ | |||||
| public class IgnoredTestResult extends TestResult { | |||||
| private List<IgnoredTestListener> listeners = new ArrayList<IgnoredTestListener>(); | |||||
| private List<TestIgnored> ignored = new ArrayList<TestIgnored>(); | |||||
| private List<TestIgnored> skipped = new ArrayList<TestIgnored>(); | |||||
| public IgnoredTestResult() { | |||||
| super(); | |||||
| } | |||||
| public synchronized void addListener(TestListener listener) { | |||||
| if (listener instanceof IgnoredTestListener) { | |||||
| listeners.add((IgnoredTestListener)listener); | |||||
| } | |||||
| super.addListener(listener); | |||||
| } | |||||
| public synchronized void removeListener(TestListener listener) { | |||||
| if (listener instanceof IgnoredTestListener) { | |||||
| listeners.remove(listener); | |||||
| } | |||||
| super.removeListener(listener); | |||||
| } | |||||
| /** | |||||
| * Record a test as having been ignored, normally by the @Ignore annotation. | |||||
| * @param test the test that was ignored. | |||||
| * @throws Exception is the listener thrown an exception on handling the notification. | |||||
| */ | |||||
| public synchronized void testIgnored(Test test) throws Exception { | |||||
| ignored.add(new TestIgnored(test)); | |||||
| for (IgnoredTestListener listener : listeners) { | |||||
| listener.testIgnored(test); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Report how many tests were ignored. | |||||
| * @return the number of tests reported as ignored during the current execution. | |||||
| */ | |||||
| public long ignoredCount() { | |||||
| return ignored.size(); | |||||
| } | |||||
| /** | |||||
| * Records a test as having an assumption failure so JUnit will no longer be executing it. | |||||
| * Under normal circumstances this would be counted as a skipped test. | |||||
| * @param test the test to record | |||||
| * @param cause the details of the test and assumption failure. | |||||
| */ | |||||
| public void testAssumptionFailure(Test test, Throwable cause) { | |||||
| skipped.add(new TestIgnored(test)); | |||||
| for (IgnoredTestListener listener : listeners) { | |||||
| listener.testAssumptionFailure(test, cause); | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Report how many tests has assumption failures. | |||||
| * @return the number of tests that reported assumption failures during the current execution. | |||||
| */ | |||||
| public long skippedCount() { | |||||
| return skipped.size(); | |||||
| } | |||||
| } | |||||
| @@ -20,20 +20,16 @@ package org.apache.tools.ant.taskdefs.optional.junit; | |||||
| import java.util.Iterator; | import java.util.Iterator; | ||||
| import java.util.List; | import java.util.List; | ||||
| import junit.framework.JUnit4TestAdapterCache; | |||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import junit.framework.TestResult; | import junit.framework.TestResult; | ||||
| import org.junit.runner.Description; | import org.junit.runner.Description; | ||||
| import org.junit.runner.Request; | import org.junit.runner.Request; | ||||
| import org.junit.runner.Runner; | import org.junit.runner.Runner; | ||||
| import org.junit.runner.manipulation.Filter; | import org.junit.runner.manipulation.Filter; | ||||
| import org.junit.runner.notification.Failure; | |||||
| import org.junit.runner.notification.RunListener; | |||||
| import org.junit.runner.notification.RunNotifier; | |||||
| /** | /** | ||||
| * Adapter between JUnit 3.8.x API and JUnit 4.x API for execution of tests | * Adapter between JUnit 3.8.x API and JUnit 4.x API for execution of tests | ||||
| * and listening of events (test start, test finish, test failure). | |||||
| * and listening of events (test start, test finish, test failure, test skipped). | |||||
| * The constructor is passed a JUnit 4 test class and a list of name of methods | * The constructor is passed a JUnit 4 test class and a list of name of methods | ||||
| * in it that should be executed. Method {@link #run run(TestResult)} executes | * in it that should be executed. Method {@link #run run(TestResult)} executes | ||||
| * the given JUnit-4-style test methods and notifies the given {@code TestResult} | * the given JUnit-4-style test methods and notifies the given {@code TestResult} | ||||
| @@ -46,7 +42,7 @@ public class JUnit4TestMethodAdapter implements Test { | |||||
| private final Class testClass; | private final Class testClass; | ||||
| private final String[] methodNames; | private final String[] methodNames; | ||||
| private final Runner runner; | private final Runner runner; | ||||
| private final Cache cache; | |||||
| private final CustomJUnit4TestAdapterCache cache; | |||||
| /** | /** | ||||
| * Creates a new adapter for the given class and a method within the class. | * Creates a new adapter for the given class and a method within the class. | ||||
| @@ -75,7 +71,7 @@ public class JUnit4TestMethodAdapter implements Test { | |||||
| } | } | ||||
| this.testClass = testClass; | this.testClass = testClass; | ||||
| this.methodNames = (String[]) methodNames.clone(); | this.methodNames = (String[]) methodNames.clone(); | ||||
| this.cache = Cache.instance; | |||||
| this.cache = CustomJUnit4TestAdapterCache.getInstance(); | |||||
| // Warning: If 'testClass' is an old-style (pre-JUnit-4) class, | // Warning: If 'testClass' is an old-style (pre-JUnit-4) class, | ||||
| // then all its test methods will be executed by the returned runner! | // then all its test methods will be executed by the returned runner! | ||||
| @@ -104,7 +100,7 @@ public class JUnit4TestMethodAdapter implements Test { | |||||
| public Class getTestClass() { | public Class getTestClass() { | ||||
| return testClass; | return testClass; | ||||
| } | } | ||||
| public void run(final TestResult result) { | public void run(final TestResult result) { | ||||
| runner.run(cache.getNotifier(result)); | runner.run(cache.getNotifier(result)); | ||||
| } | } | ||||
| @@ -188,42 +184,5 @@ public class JUnit4TestMethodAdapter implements Test { | |||||
| } | } | ||||
| /** | |||||
| * Effectively a copy of {@code JUnit4TestAdapterCache}, except that its | |||||
| * method {@code getNotifier()} does not require an argument | |||||
| * of type {@code JUnit4TestAdapter}. | |||||
| */ | |||||
| private static final class Cache extends JUnit4TestAdapterCache { | |||||
| private static final long serialVersionUID = 8454901854293461610L; | |||||
| private static final Cache instance = new Cache(); | |||||
| public static JUnit4TestAdapterCache getDefault() { | |||||
| return instance; | |||||
| } | |||||
| public RunNotifier getNotifier(final TestResult result) { | |||||
| RunNotifier notifier = new RunNotifier(); | |||||
| notifier.addListener(new RunListener() { | |||||
| public void testFailure(Failure failure) throws Exception { | |||||
| result.addError(asTest(failure.getDescription()), | |||||
| failure.getException()); | |||||
| } | |||||
| public void testFinished(Description description) | |||||
| throws Exception { | |||||
| result.endTest(asTest(description)); | |||||
| } | |||||
| public void testStarted(Description description) | |||||
| throws Exception { | |||||
| result.startTest(asTest(description)); | |||||
| } | |||||
| }); | |||||
| return notifier; | |||||
| } | |||||
| } | |||||
| } | } | ||||
| @@ -1645,7 +1645,7 @@ public class JUnitTask extends Task { | |||||
| classLoader.setThreadContextLoader(); | classLoader.setThreadContextLoader(); | ||||
| } | } | ||||
| test.setCounts(1, 0, 1); | |||||
| test.setCounts(1, 0, 1, 0); | |||||
| test.setProperties(getProject().getProperties()); | test.setProperties(getProject().getProperties()); | ||||
| for (int i = 0; i < feArray.length; i++) { | for (int i = 0; i < feArray.length; i++) { | ||||
| FormatterElement fe = feArray[i]; | FormatterElement fe = feArray[i]; | ||||
| @@ -62,6 +62,11 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
| // part of the result. So we'd better derive a new class from TestResult | // part of the result. So we'd better derive a new class from TestResult | ||||
| // and deal with it. (SB) | // and deal with it. (SB) | ||||
| private long runs, failures, errors; | private long runs, failures, errors; | ||||
| /** | |||||
| @since Ant 1.9.0 | |||||
| */ | |||||
| private long skips; | |||||
| private long runTime; | private long runTime; | ||||
| // Snapshot of the system properties | // Snapshot of the system properties | ||||
| @@ -352,16 +357,31 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
| } | } | ||||
| /** | /** | ||||
| * Set the number of runs, failures and errors. | |||||
| * Set the number of runs, failures, errors, and skipped tests. | |||||
| * @param runs the number of runs. | * @param runs the number of runs. | ||||
| * @param failures the number of failures. | * @param failures the number of failures. | ||||
| * @param errors the number of errors. | * @param errors the number of errors. | ||||
| * Kept for backward compatibility with Ant 1.8.4 | |||||
| */ | */ | ||||
| public void setCounts(long runs, long failures, long errors) { | public void setCounts(long runs, long failures, long errors) { | ||||
| this.runs = runs; | this.runs = runs; | ||||
| this.failures = failures; | this.failures = failures; | ||||
| this.errors = errors; | this.errors = errors; | ||||
| } | } | ||||
| /** | |||||
| * Set the number of runs, failures, errors, and skipped tests. | |||||
| * @param runs the number of runs. | |||||
| * @param failures the number of failures. | |||||
| * @param errors the number of errors. | |||||
| * @param skips the number of skipped tests. | |||||
| * @since Ant 1.9.0 | |||||
| */ | |||||
| public void setCounts(long runs, long failures, long errors, long skips) { | |||||
| this.runs = runs; | |||||
| this.failures = failures; | |||||
| this.errors = errors; | |||||
| this.skips = skips; | |||||
| } | |||||
| /** | /** | ||||
| * Set the runtime. | * Set the runtime. | ||||
| @@ -395,6 +415,14 @@ public class JUnitTest extends BaseTest implements Cloneable { | |||||
| return errors; | return errors; | ||||
| } | } | ||||
| /** | |||||
| * Get the number of skipped tests. | |||||
| * @return the number of skipped tests. | |||||
| */ | |||||
| public long skipCount() { | |||||
| return skips; | |||||
| } | |||||
| /** | /** | ||||
| * Get the run time. | * Get the run time. | ||||
| * @return the run time in milliseconds. | * @return the run time in milliseconds. | ||||
| @@ -36,6 +36,7 @@ import java.util.Properties; | |||||
| import java.util.StringTokenizer; | import java.util.StringTokenizer; | ||||
| import java.util.Vector; | import java.util.Vector; | ||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.JUnit4TestAdapterCache; | |||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import junit.framework.TestFailure; | import junit.framework.TestFailure; | ||||
| import junit.framework.TestListener; | import junit.framework.TestListener; | ||||
| @@ -76,7 +77,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| /** | /** | ||||
| * Collects TestResults. | * Collects TestResults. | ||||
| */ | */ | ||||
| private TestResult res; | |||||
| private IgnoredTestResult res; | |||||
| /** | /** | ||||
| * Do we filter junit.*.* stack frames out of failure and error exceptions. | * Do we filter junit.*.* stack frames out of failure and error exceptions. | ||||
| @@ -289,6 +290,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| boolean filtertrace, boolean haltOnFailure, | boolean filtertrace, boolean haltOnFailure, | ||||
| boolean showOutput, boolean logTestListenerEvents, | boolean showOutput, boolean logTestListenerEvents, | ||||
| ClassLoader loader) { | ClassLoader loader) { | ||||
| super(); | |||||
| JUnitTestRunner.filtertrace = filtertrace; // XXX clumsy, should use instance field somehow | JUnitTestRunner.filtertrace = filtertrace; // XXX clumsy, should use instance field somehow | ||||
| this.junitTest = test; | this.junitTest = test; | ||||
| this.haltOnError = haltOnError; | this.haltOnError = haltOnError; | ||||
| @@ -350,7 +352,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| * Run the test. | * Run the test. | ||||
| */ | */ | ||||
| public void run() { | public void run() { | ||||
| res = new TestResult(); | |||||
| res = new IgnoredTestResult(); | |||||
| res.addListener(wrapListener(this)); | res.addListener(wrapListener(this)); | ||||
| final int size = formatters.size(); | final int size = formatters.size(); | ||||
| for (int i = 0; i < size; i++) { | for (int i = 0; i < size; i++) { | ||||
| @@ -468,8 +470,8 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| formalParams = new Class[] {Class.class, String[].class}; | formalParams = new Class[] {Class.class, String[].class}; | ||||
| actualParams = new Object[] {testClass, methods}; | actualParams = new Object[] {testClass, methods}; | ||||
| } else { | } else { | ||||
| formalParams = new Class[] {Class.class}; | |||||
| actualParams = new Object[] {testClass}; | |||||
| formalParams = new Class[] {Class.class, JUnit4TestAdapterCache.class}; | |||||
| actualParams = new Object[] {testClass, CustomJUnit4TestAdapterCache.getInstance()}; | |||||
| } | } | ||||
| suite = | suite = | ||||
| (Test) junit4TestAdapterClass | (Test) junit4TestAdapterClass | ||||
| @@ -512,7 +514,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| ((TestListener) formatters.elementAt(i)) | ((TestListener) formatters.elementAt(i)) | ||||
| .addError(null, exception); | .addError(null, exception); | ||||
| } | } | ||||
| junitTest.setCounts(1, 0, 1); | |||||
| junitTest.setCounts(1, 0, 1, 0); | |||||
| junitTest.setRunTime(0); | junitTest.setRunTime(0); | ||||
| } else { | } else { | ||||
| try { | try { | ||||
| @@ -522,10 +524,10 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| if (junit4 || | if (junit4 || | ||||
| suite.getClass().getName().equals(JUNIT_4_TEST_ADAPTER)) { | suite.getClass().getName().equals(JUNIT_4_TEST_ADAPTER)) { | ||||
| int[] cnts = findJUnit4FailureErrorCount(res); | int[] cnts = findJUnit4FailureErrorCount(res); | ||||
| junitTest.setCounts(res.runCount(), cnts[0], cnts[1]); | |||||
| junitTest.setCounts(res.runCount() + res.ignoredCount(), cnts[0], cnts[1], res.ignoredCount() + res.skippedCount()); | |||||
| } else { | } else { | ||||
| junitTest.setCounts(res.runCount(), res.failureCount(), | |||||
| res.errorCount()); | |||||
| junitTest.setCounts(res.runCount() + res.ignoredCount(), res.failureCount(), | |||||
| res.errorCount(), res.ignoredCount() + res.skippedCount()); | |||||
| } | } | ||||
| junitTest.setRunTime(System.currentTimeMillis() - start); | junitTest.setRunTime(System.currentTimeMillis() - start); | ||||
| } | } | ||||
| @@ -1101,8 +1103,8 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR | |||||
| * | * | ||||
| * @since Ant 1.7 | * @since Ant 1.7 | ||||
| */ | */ | ||||
| private TestListener wrapListener(final TestListener testListener) { | |||||
| return new TestListener() { | |||||
| private TestListenerWrapper wrapListener(final TestListener testListener) { | |||||
| return new TestListenerWrapper(testListener) { | |||||
| public void addError(Test test, Throwable t) { | public void addError(Test test, Throwable t) { | ||||
| if (junit4 && t instanceof AssertionFailedError) { | if (junit4 && t instanceof AssertionFailedError) { | ||||
| // JUnit 4 does not distinguish between errors and failures | // JUnit 4 does not distinguish between errors and failures | ||||
| @@ -26,11 +26,14 @@ import java.text.NumberFormat; | |||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.JUnit4TestCaseFacade; | |||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.apache.tools.ant.util.StringUtils; | import org.apache.tools.ant.util.StringUtils; | ||||
| import org.junit.Ignore; | |||||
| import org.junit.runner.notification.Failure; | |||||
| /** | /** | ||||
| @@ -38,7 +41,7 @@ import org.apache.tools.ant.util.StringUtils; | |||||
| * | * | ||||
| */ | */ | ||||
| public class PlainJUnitResultFormatter implements JUnitResultFormatter { | |||||
| public class PlainJUnitResultFormatter implements JUnitResultFormatter, IgnoredTestListener { | |||||
| private static final double ONE_SECOND = 1000.0; | private static final double ONE_SECOND = 1000.0; | ||||
| @@ -123,6 +126,8 @@ public class PlainJUnitResultFormatter implements JUnitResultFormatter { | |||||
| sb.append(suite.failureCount()); | sb.append(suite.failureCount()); | ||||
| sb.append(", Errors: "); | sb.append(", Errors: "); | ||||
| sb.append(suite.errorCount()); | sb.append(suite.errorCount()); | ||||
| sb.append(", Skipped: "); | |||||
| sb.append(suite.skipCount()); | |||||
| sb.append(", Time elapsed: "); | sb.append(", Time elapsed: "); | ||||
| sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); | sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); | ||||
| sb.append(" sec"); | sb.append(" sec"); | ||||
| @@ -258,4 +263,40 @@ public class PlainJUnitResultFormatter implements JUnitResultFormatter { | |||||
| } | } | ||||
| } | } | ||||
| @Override | |||||
| public void testIgnored(Test test) { | |||||
| String message = null; | |||||
| if (test instanceof JUnit4TestCaseFacade) { | |||||
| JUnit4TestCaseFacade facade = (JUnit4TestCaseFacade) test; | |||||
| Ignore annotation = facade.getDescription().getAnnotation(Ignore.class); | |||||
| if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { | |||||
| message = annotation.value(); | |||||
| } | |||||
| } | |||||
| formatSkip(test, message); | |||||
| } | |||||
| public void formatSkip(Test test, String message) { | |||||
| if (test != null) { | |||||
| endTest(test); | |||||
| } | |||||
| try { | |||||
| wri.write("\tSKIPPED"); | |||||
| if (message != null) { | |||||
| wri.write(": "); | |||||
| wri.write(message); | |||||
| } | |||||
| wri.newLine(); | |||||
| } catch (IOException ex) { | |||||
| throw new BuildException(ex); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void testAssumptionFailure(Test test, Throwable throwable) { | |||||
| formatSkip(test, throwable.getMessage()); | |||||
| } | |||||
| } // PlainJUnitResultFormatter | } // PlainJUnitResultFormatter | ||||
| @@ -144,6 +144,8 @@ public class SummaryJUnitResultFormatter | |||||
| sb.append(suite.failureCount()); | sb.append(suite.failureCount()); | ||||
| sb.append(", Errors: "); | sb.append(", Errors: "); | ||||
| sb.append(suite.errorCount()); | sb.append(suite.errorCount()); | ||||
| sb.append(", Skipped: "); | |||||
| sb.append(suite.skipCount()); | |||||
| sb.append(", Time elapsed: "); | sb.append(", Time elapsed: "); | ||||
| sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); | sb.append(nf.format(suite.getRunTime() / ONE_SECOND)); | ||||
| sb.append(" sec"); | sb.append(" sec"); | ||||
| @@ -0,0 +1,35 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You 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.apache.tools.ant.taskdefs.optional.junit; | |||||
| import junit.framework.Test; | |||||
| public class TestIgnored { | |||||
| private Test test; | |||||
| public TestIgnored(Test test) { | |||||
| this.test = test; | |||||
| } | |||||
| public Test getTest() { | |||||
| return test; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,74 @@ | |||||
| /* | |||||
| * Licensed to the Apache Software Foundation (ASF) under one or more | |||||
| * contributor license agreements. See the NOTICE file distributed with | |||||
| * this work for additional information regarding copyright ownership. | |||||
| * The ASF licenses this file to You 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.apache.tools.ant.taskdefs.optional.junit; | |||||
| import junit.framework.AssertionFailedError; | |||||
| import junit.framework.JUnit4TestAdapterCache; | |||||
| import junit.framework.Test; | |||||
| import junit.framework.TestListener; | |||||
| import org.junit.internal.AssumptionViolatedException; | |||||
| import org.junit.runner.Description; | |||||
| import org.junit.runner.notification.Failure; | |||||
| public class TestListenerWrapper implements TestListener, IgnoredTestListener { | |||||
| private TestListener wrapped; | |||||
| public TestListenerWrapper(TestListener listener) { | |||||
| super(); | |||||
| wrapped = listener; | |||||
| } | |||||
| @Override | |||||
| public void addError(Test test, Throwable throwable) { | |||||
| wrapped.addError(test, throwable); | |||||
| } | |||||
| @Override | |||||
| public void addFailure(Test test, AssertionFailedError assertionFailedError) { | |||||
| wrapped.addFailure(test, assertionFailedError); | |||||
| } | |||||
| @Override | |||||
| public void endTest(Test test) { | |||||
| wrapped.endTest(test); | |||||
| } | |||||
| @Override | |||||
| public void startTest(Test test) { | |||||
| wrapped.startTest(test); | |||||
| } | |||||
| @Override | |||||
| public void testIgnored(Test test) { | |||||
| if (wrapped instanceof IgnoredTestListener) { | |||||
| ((IgnoredTestListener)wrapped).testIgnored(test); | |||||
| } | |||||
| } | |||||
| @Override | |||||
| public void testAssumptionFailure(Test test, Throwable throwable) { | |||||
| if (wrapped instanceof IgnoredTestListener) { | |||||
| ((IgnoredTestListener)wrapped).testAssumptionFailure(test, throwable); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -106,6 +106,8 @@ public interface XMLConstants { | |||||
| /** tests attribute for testsuite elements */ | /** tests attribute for testsuite elements */ | ||||
| String ATTR_TESTS = "tests"; | String ATTR_TESTS = "tests"; | ||||
| String ATTR_SKIPPED = "skipped"; | |||||
| /** type attribute for failure and error elements */ | /** type attribute for failure and error elements */ | ||||
| String ATTR_TYPE = "type"; | String ATTR_TYPE = "type"; | ||||
| @@ -23,20 +23,26 @@ import java.io.IOException; | |||||
| import java.io.OutputStream; | import java.io.OutputStream; | ||||
| import java.io.OutputStreamWriter; | import java.io.OutputStreamWriter; | ||||
| import java.io.Writer; | import java.io.Writer; | ||||
| import java.lang.reflect.Method; | |||||
| import java.net.InetAddress; | |||||
| import java.net.UnknownHostException; | |||||
| import java.util.Date; | |||||
| import java.util.Enumeration; | import java.util.Enumeration; | ||||
| import java.util.Hashtable; | import java.util.Hashtable; | ||||
| import java.util.Properties; | import java.util.Properties; | ||||
| import java.util.Date; | |||||
| import java.net.InetAddress; | |||||
| import java.net.UnknownHostException; | |||||
| import javax.xml.parsers.DocumentBuilder; | import javax.xml.parsers.DocumentBuilder; | ||||
| import javax.xml.parsers.DocumentBuilderFactory; | import javax.xml.parsers.DocumentBuilderFactory; | ||||
| import junit.framework.AssertionFailedError; | import junit.framework.AssertionFailedError; | ||||
| import junit.framework.JUnit4TestCaseFacade; | |||||
| import junit.framework.Test; | import junit.framework.Test; | ||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.util.DOMElementWriter; | import org.apache.tools.ant.util.DOMElementWriter; | ||||
| import org.apache.tools.ant.util.DateUtils; | import org.apache.tools.ant.util.DateUtils; | ||||
| import org.apache.tools.ant.util.FileUtils; | import org.apache.tools.ant.util.FileUtils; | ||||
| import org.junit.Ignore; | |||||
| import org.w3c.dom.Document; | import org.w3c.dom.Document; | ||||
| import org.w3c.dom.Element; | import org.w3c.dom.Element; | ||||
| import org.w3c.dom.Text; | import org.w3c.dom.Text; | ||||
| @@ -48,7 +54,7 @@ import org.w3c.dom.Text; | |||||
| * @see FormatterElement | * @see FormatterElement | ||||
| */ | */ | ||||
| public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants { | |||||
| public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstants, IgnoredTestListener { | |||||
| private static final double ONE_SECOND = 1000.0; | private static final double ONE_SECOND = 1000.0; | ||||
| @@ -73,16 +79,29 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| private Element rootElement; | private Element rootElement; | ||||
| /** | /** | ||||
| * Element for the current test. | * Element for the current test. | ||||
| * | |||||
| * The keying of this map is a bit of a hack: tests are keyed by caseName(className) since | |||||
| * the Test we get for Test-start isn't the same as the Test we get during test-assumption-fail, | |||||
| * so we can't easily match Test objects without manually iterating over all keys and checking | |||||
| * individual fields. | |||||
| */ | */ | ||||
| private Hashtable testElements = new Hashtable(); | |||||
| private Hashtable<String, Element> testElements = new Hashtable<String, Element>(); | |||||
| /** | /** | ||||
| * tests that failed. | * tests that failed. | ||||
| */ | */ | ||||
| private Hashtable failedTests = new Hashtable(); | private Hashtable failedTests = new Hashtable(); | ||||
| /** | |||||
| * Tests that were skipped. | |||||
| */ | |||||
| private Hashtable<String, Test> skippedTests = new Hashtable<String, Test>(); | |||||
| /** | |||||
| * Tests that were ignored. See the note above about the key being a bit of a hack. | |||||
| */ | |||||
| private Hashtable<String, Test> ignoredTests = new Hashtable<String, Test>(); | |||||
| /** | /** | ||||
| * Timing helper. | * Timing helper. | ||||
| */ | */ | ||||
| private Hashtable testStarts = new Hashtable(); | |||||
| private Hashtable<String, Long> testStarts = new Hashtable<String, Long>(); | |||||
| /** | /** | ||||
| * Where to write the log to. | * Where to write the log to. | ||||
| */ | */ | ||||
| @@ -161,6 +180,7 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount()); | rootElement.setAttribute(ATTR_TESTS, "" + suite.runCount()); | ||||
| rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount()); | rootElement.setAttribute(ATTR_FAILURES, "" + suite.failureCount()); | ||||
| rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount()); | rootElement.setAttribute(ATTR_ERRORS, "" + suite.errorCount()); | ||||
| rootElement.setAttribute(ATTR_SKIPPED, "" + suite.skipCount()); | |||||
| rootElement.setAttribute( | rootElement.setAttribute( | ||||
| ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND)); | ATTR_TIME, "" + (suite.getRunTime() / ONE_SECOND)); | ||||
| if (out != null) { | if (out != null) { | ||||
| @@ -193,9 +213,13 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| * @param t the test. | * @param t the test. | ||||
| */ | */ | ||||
| public void startTest(Test t) { | public void startTest(Test t) { | ||||
| testStarts.put(t, new Long(System.currentTimeMillis())); | |||||
| testStarts.put(createDescription(t), System.currentTimeMillis()); | |||||
| } | } | ||||
| private static String createDescription(Test test) throws BuildException { | |||||
| return JUnitVersionHelper.getTestCaseName(test) + "(" + JUnitVersionHelper.getTestCaseClassName(test) + ")"; | |||||
| } | |||||
| /** | /** | ||||
| * Interface TestListener. | * Interface TestListener. | ||||
| * | * | ||||
| @@ -203,15 +227,16 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| * @param test the test. | * @param test the test. | ||||
| */ | */ | ||||
| public void endTest(Test test) { | public void endTest(Test test) { | ||||
| String testDescription = createDescription(test); | |||||
| // Fix for bug #5637 - if a junit.extensions.TestSetup is | // Fix for bug #5637 - if a junit.extensions.TestSetup is | ||||
| // used and throws an exception during setUp then startTest | // used and throws an exception during setUp then startTest | ||||
| // would never have been called | // would never have been called | ||||
| if (!testStarts.containsKey(test)) { | |||||
| if (!testStarts.containsKey(testDescription)) { | |||||
| startTest(test); | startTest(test); | ||||
| } | } | ||||
| Element currentTest = null; | |||||
| if (!failedTests.containsKey(test)) { | |||||
| Element currentTest; | |||||
| if (!failedTests.containsKey(test) && !skippedTests.containsKey(testDescription) && !ignoredTests.containsKey(testDescription)) { | |||||
| currentTest = doc.createElement(TESTCASE); | currentTest = doc.createElement(TESTCASE); | ||||
| String n = JUnitVersionHelper.getTestCaseName(test); | String n = JUnitVersionHelper.getTestCaseName(test); | ||||
| currentTest.setAttribute(ATTR_NAME, | currentTest.setAttribute(ATTR_NAME, | ||||
| @@ -221,15 +246,14 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| currentTest.setAttribute(ATTR_CLASSNAME, | currentTest.setAttribute(ATTR_CLASSNAME, | ||||
| JUnitVersionHelper.getTestCaseClassName(test)); | JUnitVersionHelper.getTestCaseClassName(test)); | ||||
| rootElement.appendChild(currentTest); | rootElement.appendChild(currentTest); | ||||
| testElements.put(test, currentTest); | |||||
| testElements.put(createDescription(test), currentTest); | |||||
| } else { | } else { | ||||
| currentTest = (Element) testElements.get(test); | |||||
| currentTest = testElements.get(testDescription); | |||||
| } | } | ||||
| Long l = (Long) testStarts.get(test); | |||||
| Long l = testStarts.get(createDescription(test)); | |||||
| currentTest.setAttribute(ATTR_TIME, | currentTest.setAttribute(ATTR_TIME, | ||||
| "" + ((System.currentTimeMillis() | |||||
| - l.longValue()) / ONE_SECOND)); | |||||
| "" + ((System.currentTimeMillis() - l) / ONE_SECOND)); | |||||
| } | } | ||||
| /** | /** | ||||
| @@ -272,9 +296,9 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| } | } | ||||
| Element nested = doc.createElement(type); | Element nested = doc.createElement(type); | ||||
| Element currentTest = null; | |||||
| Element currentTest; | |||||
| if (test != null) { | if (test != null) { | ||||
| currentTest = (Element) testElements.get(test); | |||||
| currentTest = testElements.get(createDescription(test)); | |||||
| } else { | } else { | ||||
| currentTest = rootElement; | currentTest = rootElement; | ||||
| } | } | ||||
| @@ -298,4 +322,63 @@ public class XMLJUnitResultFormatter implements JUnitResultFormatter, XMLConstan | |||||
| nested.appendChild(doc.createCDATASection(output)); | nested.appendChild(doc.createCDATASection(output)); | ||||
| } | } | ||||
| @Override | |||||
| public void testIgnored(Test test) { | |||||
| String message = null; | |||||
| if (test != null && test instanceof JUnit4TestCaseFacade) { | |||||
| //try and get the message coded as part of the ignore | |||||
| /* | |||||
| * org.junit.runner.Description contains a getAnnotation(Class) method... but this | |||||
| * wasn't in older versions of JUnit4 so we have to try and do this by reflection | |||||
| */ | |||||
| try { | |||||
| Class<?> testClass = Class.forName(JUnitVersionHelper.getTestCaseClassName(test)); | |||||
| Method testMethod = testClass.getMethod(JUnitVersionHelper.getTestCaseName(test)); | |||||
| Ignore annotation = testMethod.getAnnotation(Ignore.class); | |||||
| if (annotation != null && annotation.value() != null && !annotation.value().isEmpty()) { | |||||
| message = annotation.value(); | |||||
| } | |||||
| } catch (NoSuchMethodException e) { | |||||
| // silently ignore - we'll report a skip with no message | |||||
| } catch (ClassNotFoundException e) { | |||||
| // silently ignore - we'll report a skip with no message | |||||
| } | |||||
| } | |||||
| formatSkip(test, message); | |||||
| if (test != null) { | |||||
| ignoredTests.put(createDescription(test), test); | |||||
| } | |||||
| } | |||||
| public void formatSkip(Test test, String message) { | |||||
| if (test != null) { | |||||
| endTest(test); | |||||
| } | |||||
| Element nested = doc.createElement("skipped"); | |||||
| if (message != null) { | |||||
| nested.setAttribute("message", message); | |||||
| } | |||||
| Element currentTest; | |||||
| if (test != null) { | |||||
| currentTest = testElements.get(createDescription(test)); | |||||
| } else { | |||||
| currentTest = rootElement; | |||||
| } | |||||
| currentTest.appendChild(nested); | |||||
| } | |||||
| @Override | |||||
| public void testAssumptionFailure(Test test, Throwable failure) { | |||||
| String message = failure.getMessage(); | |||||
| formatSkip(test, message); | |||||
| skippedTests.put(createDescription(test), test); | |||||
| } | |||||
| } // XMLJUnitResultFormatter | } // XMLJUnitResultFormatter | ||||
| @@ -20,6 +20,7 @@ | |||||
| <path id="junit"> | <path id="junit"> | ||||
| <fileset dir="../../../../../../lib/optional" includes="junit*" /> | <fileset dir="../../../../../../lib/optional" includes="junit*" /> | ||||
| <fileset dir="../../../../../../lib/optional" includes="hamcrest-core*" /> | |||||
| </path> | </path> | ||||
| <macrodef name="empty-test"> | <macrodef name="empty-test"> | ||||
| @@ -25,6 +25,14 @@ import java.io.IOException; | |||||
| import org.apache.tools.ant.BuildException; | import org.apache.tools.ant.BuildException; | ||||
| import org.apache.tools.ant.BuildFileTest; | import org.apache.tools.ant.BuildFileTest; | ||||
| import org.apache.tools.ant.util.JavaEnvUtils; | import org.apache.tools.ant.util.JavaEnvUtils; | ||||
| import org.w3c.dom.Document; | |||||
| import org.w3c.dom.Node; | |||||
| import javax.xml.parsers.DocumentBuilder; | |||||
| import javax.xml.parsers.DocumentBuilderFactory; | |||||
| import javax.xml.xpath.XPath; | |||||
| import javax.xml.xpath.XPathConstants; | |||||
| import javax.xml.xpath.XPathFactory; | |||||
| public class JUnitTaskTest extends BuildFileTest { | public class JUnitTaskTest extends BuildFileTest { | ||||
| @@ -262,7 +270,7 @@ public class JUnitTaskTest extends BuildFileTest { | |||||
| line); | line); | ||||
| line = reader.readLine(); | line = reader.readLine(); | ||||
| assertNotNull(line); | assertNotNull(line); | ||||
| assertTrue(line.startsWith("Tests run: 1, Failures: 0, Errors: 0, Time elapsed:")); | |||||
| assertTrue(line.startsWith("Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed:")); | |||||
| line = reader.readLine(); | line = reader.readLine(); | ||||
| assertEquals("------------- Standard Output ---------------", | assertEquals("------------- Standard Output ---------------", | ||||
| line); | line); | ||||
| @@ -296,4 +304,33 @@ public class JUnitTaskTest extends BuildFileTest { | |||||
| assertEquals(search, line); | assertEquals(search, line); | ||||
| } | } | ||||
| public void testJunit4Skip() throws Exception { | |||||
| executeTarget("testSkippableTests"); | |||||
| DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); | |||||
| DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); | |||||
| Document doc = dBuilder.parse(getProject().getResource("out/TEST-org.example.junit.Junit4Skippable.xml").getInputStream()); | |||||
| assertEquals("Incorrect number of nodes created", 8, doc.getElementsByTagName("testcase").getLength()); | |||||
| XPathFactory factory = XPathFactory.newInstance(); | |||||
| XPath xpath = factory.newXPath(); | |||||
| assertEquals("Incorrect number of skipped tests in header", 4, Integer.parseInt(xpath.compile("//testsuite/@skipped").evaluate(doc))); | |||||
| assertEquals("Incorrect number of error tests in header", 1, Integer.parseInt(xpath.compile("//testsuite/@errors").evaluate(doc))); | |||||
| assertEquals("Incorrect number of failure tests in header", 2, Integer.parseInt(xpath.compile("//testsuite/@failures").evaluate(doc))); | |||||
| assertEquals("Incorrect number of tests in header", 8, Integer.parseInt(xpath.compile("//testsuite/@tests").evaluate(doc))); | |||||
| assertEquals("Incorrect ignore message on explicit ignored test", "Please don't ignore me!", xpath.compile("//testsuite/testcase[@name='explicitIgnoreTest']/skipped/@message").evaluate(doc)); | |||||
| assertEquals("No message should be set on Ignored tests with no Ignore annotation text", 0, ((Node)xpath.compile("//testsuite/testcase[@name='explicitlyIgnoreTestNoMessage']/skipped").evaluate(doc, XPathConstants.NODE)).getAttributes().getLength()); | |||||
| assertEquals("Incorrect ignore message on implicit ignored test", "This test will be ignored", xpath.compile("//testsuite/testcase[@name='implicitlyIgnoreTest']/skipped/@message").evaluate(doc)); | |||||
| assertNotNull("Implicit ignore test should have an ignore element", xpath.compile("//testsuite/testcase[@name='implicitlyIgnoreTestNoMessage']/skipped").evaluate(doc, XPathConstants.NODE)); | |||||
| } | |||||
| public void testTestMethods() throws Exception { | |||||
| executeTarget("testTestMethods"); | |||||
| } | |||||
| } | } | ||||
| @@ -0,0 +1,56 @@ | |||||
| package org.example.junit; | |||||
| import org.junit.Assume; | |||||
| import org.junit.Ignore; | |||||
| import org.junit.Test; | |||||
| import static org.junit.Assert.assertTrue; | |||||
| import static org.junit.Assert.fail; | |||||
| public class Junit4Skippable { | |||||
| @Test | |||||
| public void passingTest() { | |||||
| assertTrue("This test passed", true); | |||||
| } | |||||
| @Ignore("Please don't ignore me!") | |||||
| @Test | |||||
| public void explicitIgnoreTest() { | |||||
| fail("This test should be skipped"); | |||||
| } | |||||
| @Test | |||||
| public void implicitlyIgnoreTest() { | |||||
| Assume.assumeFalse("This test will be ignored", true); | |||||
| fail("I told you, this test should have been ignored!"); | |||||
| } | |||||
| @Test | |||||
| @Ignore | |||||
| public void explicitlyIgnoreTestNoMessage() { | |||||
| fail("This test should be skipped"); | |||||
| } | |||||
| @Test | |||||
| public void implicitlyIgnoreTestNoMessage() { | |||||
| Assume.assumeFalse(true); | |||||
| fail("I told you, this test should have been ignored!"); | |||||
| } | |||||
| @Test | |||||
| public void failingTest() { | |||||
| fail("I told you this test was going to fail"); | |||||
| } | |||||
| @Test | |||||
| public void failingTestNoMessage() { | |||||
| fail(); | |||||
| } | |||||
| @Test | |||||
| public void errorTest() { | |||||
| throw new RuntimeException("Whoops, this test went wrong"); | |||||
| } | |||||
| } | |||||