|
Ant example source code file (JUnitTestRunner.java)
The JUnitTestRunner.java source code
/*
* 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.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.Vector;
import junit.framework.AssertionFailedError;
import junit.framework.Test;
import junit.framework.TestFailure;
import junit.framework.TestListener;
import junit.framework.TestResult;
import junit.framework.TestSuite;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Permissions;
import org.apache.tools.ant.util.StringUtils;
import org.apache.tools.ant.util.TeeOutputStream;
/**
* Simple Testrunner for JUnit that runs all tests of a testsuite.
*
* <p>This TestRunner expects a name of a TestCase class as its
* argument. If this class provides a static suite() method it will be
* called and the resulting Test will be run. So, the signature should be
* <pre>
*
* <p> If no such method exists, all public methods starting with
* "test" and taking no argument will be run.
*
* <p> Summary output is generated at the end.
*
* @since Ant 1.2
*/
public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestRunnerMirror {
/**
* Holds the registered formatters.
*/
private Vector formatters = new Vector();
/**
* Collects TestResults.
*/
private TestResult res;
/**
* Do we filter junit.*.* stack frames out of failure and error exceptions.
*/
private static boolean filtertrace = true;
/**
* Do we send output to System.out/.err in addition to the formatters?
*/
private boolean showOutput = false;
private boolean outputToFormatters = true;
/**
* The permissions set for the test to run.
*/
private Permissions perm = null;
private static final String[] DEFAULT_TRACE_FILTERS = new String[] {
"junit.framework.TestCase",
"junit.framework.TestResult",
"junit.framework.TestSuite",
"junit.framework.Assert.", // don't filter AssertionFailure
"junit.swingui.TestRunner",
"junit.awtui.TestRunner",
"junit.textui.TestRunner",
"java.lang.reflect.Method.invoke(",
"sun.reflect.",
"org.apache.tools.ant.",
// JUnit 4 support:
"org.junit.",
"junit.framework.JUnit4TestAdapter",
// See wrapListener for reason:
"Caused by: java.lang.AssertionError",
" more",
};
/**
* Do we stop on errors.
*/
private boolean haltOnError = false;
/**
* Do we stop on test failures.
*/
private boolean haltOnFailure = false;
/**
* Returncode
*/
private int retCode = SUCCESS;
/**
* The TestSuite we are currently running.
*/
private JUnitTest junitTest;
/** output written during the test */
private PrintStream systemError;
/** Error output during the test */
private PrintStream systemOut;
/** is this runner running in forked mode? */
private boolean forked = false;
/** Running more than one test suite? */
private static boolean multipleTests = false;
/** ClassLoader passed in in non-forked mode. */
private ClassLoader loader;
/** Do we print TestListener events? */
private boolean logTestListenerEvents = false;
/** Turned on if we are using JUnit 4 for this test suite. see #38811 */
private boolean junit4;
/**
* The file used to indicate that the build crashed.
* File will be empty in case the build did not crash.
*/
private static String crashFile = null;
/**
* Constructor for fork=true or when the user hasn't specified a
* classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure) {
this(test, haltOnError, filtertrace, haltOnFailure, false);
}
/**
* Constructor for fork=true or when the user hasn't specified a
* classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
* @param showOutput whether to send output to System.out/.err as well as formatters.
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput) {
this(test, haltOnError, filtertrace, haltOnFailure, showOutput, false);
}
/**
* Constructor for fork=true or when the user hasn't specified a
* classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
* @param showOutput whether to send output to System.out/.err as well as formatters.
* @param logTestListenerEvents whether to print TestListener events.
* @since Ant 1.7
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents) {
this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
logTestListenerEvents, null);
}
/**
* Constructor to use when the user has specified a classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
* @param loader the classloader to use running the test.
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
ClassLoader loader) {
this(test, haltOnError, filtertrace, haltOnFailure, false, loader);
}
/**
* Constructor to use when the user has specified a classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
* @param showOutput whether to send output to System.out/.err as well as formatters.
* @param loader the classloader to use running the test.
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, ClassLoader loader) {
this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
false, loader);
}
/**
* Constructor to use when the user has specified a classpath.
* @param test the test to run.
* @param haltOnError whether to stop the run if an error is found.
* @param filtertrace whether to filter junit.*.* stack frames out of exceptions
* @param haltOnFailure whether to stop the run if failure is found.
* @param showOutput whether to send output to System.out/.err as well as formatters.
* @param logTestListenerEvents whether to print TestListener events.
* @param loader the classloader to use running the test.
* @since Ant 1.7
*/
public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents,
ClassLoader loader) {
JUnitTestRunner.filtertrace = filtertrace;
this.junitTest = test;
this.haltOnError = haltOnError;
this.haltOnFailure = haltOnFailure;
this.showOutput = showOutput;
this.logTestListenerEvents = logTestListenerEvents;
this.loader = loader;
}
private PrintStream savedOut = null;
/**
* Run the test.
*/
public void run() {
res = new TestResult();
res.addListener(wrapListener(this));
for (int i = 0; i < formatters.size(); i++) {
res.addListener(wrapListener((TestListener) formatters.elementAt(i)));
}
ByteArrayOutputStream errStrm = new ByteArrayOutputStream();
systemError = new PrintStream(errStrm);
ByteArrayOutputStream outStrm = new ByteArrayOutputStream();
systemOut = new PrintStream(outStrm);
PrintStream savedErr = null;
if (forked) {
if (!outputToFormatters) {
if (!showOutput) {
savedOut = System.out;
savedErr = System.err;
System.setOut(
new PrintStream(
new OutputStream() {
public void write(int b) {
}
}));
System.setErr(
new PrintStream(
new OutputStream() {
public void write(int b) {
}
}));
}
} else {
savedOut = System.out;
savedErr = System.err;
if (!showOutput) {
System.setOut(systemOut);
System.setErr(systemError);
} else {
System.setOut(new PrintStream(
new TeeOutputStream(savedOut, systemOut)
)
);
System.setErr(new PrintStream(
new TeeOutputStream(savedErr,
systemError)
)
);
}
perm = null;
}
} else {
if (perm != null) {
perm.setSecurityManager();
}
}
Test suite = null;
Throwable exception = null;
boolean startTestSuiteSuccess = false;
try {
try {
Class testClass = null;
if (loader == null) {
testClass = Class.forName(junitTest.getName());
} else {
testClass = Class.forName(junitTest.getName(), true,
loader);
}
// check for a static suite method first, even when using
// JUnit 4
Method suiteMethod = null;
try {
// check if there is a suite method
suiteMethod = testClass.getMethod("suite", new Class[0]);
} catch (NoSuchMethodException e) {
// no appropriate suite method found. We don't report any
// error here since it might be perfectly normal.
}
if (suiteMethod != null) {
// if there is a suite method available, then try
// to extract the suite from it. If there is an error
// here it will be caught below and reported.
suite = (Test) suiteMethod.invoke(null, new Class[0]);
} else {
Class junit4TestAdapterClass = null;
// Check for JDK 5 first. Will *not* help on JDK 1.4
// if only junit-4.0.jar in CP because in that case
// linkage of whole task will already have failed! But
// will help if CP has junit-3.8.2.jar:junit-4.0.jar.
// In that case first C.fN will fail with CNFE and we
// will avoid UnsupportedClassVersionError.
try {
Class.forName("java.lang.annotation.Annotation");
if (loader == null) {
junit4TestAdapterClass =
Class.forName("junit.framework.JUnit4TestAdapter");
} else {
junit4TestAdapterClass =
Class.forName("junit.framework.JUnit4TestAdapter",
true, loader);
}
} catch (ClassNotFoundException e) {
// OK, fall back to JUnit 3.
}
junit4 = junit4TestAdapterClass != null;
if (junit4) {
// Let's use it!
suite =
(Test) junit4TestAdapterClass
.getConstructor(new Class[] {Class.class}).
newInstance(new Object[] {testClass});
} else {
// Use JUnit 3.
// try to extract a test suite automatically this
// will generate warnings if the class is no
// suitable Test
suite = new TestSuite(testClass);
}
}
} catch (Throwable e) {
retCode = ERRORS;
exception = e;
}
long start = System.currentTimeMillis();
fireStartTestSuite();
startTestSuiteSuccess = true;
if (exception != null) { // had an exception constructing suite
for (int i = 0; i < formatters.size(); i++) {
((TestListener) formatters.elementAt(i))
.addError(null, exception);
}
junitTest.setCounts(1, 0, 1);
junitTest.setRunTime(0);
} else {
try {
logTestListenerEvent("tests to run: " + suite.countTestCases());
suite.run(res);
} finally {
if (junit4) {
int[] cnts = findJUnit4FailureErrorCount(res);
junitTest.setCounts(res.runCount(), cnts[0], cnts[1]);
} else {
junitTest.setCounts(res.runCount(), res.failureCount(),
res.errorCount());
}
junitTest.setRunTime(System.currentTimeMillis() - start);
}
}
} finally {
if (perm != null) {
perm.restoreSecurityManager();
}
if (savedOut != null) {
System.setOut(savedOut);
}
if (savedErr != null) {
System.setErr(savedErr);
}
systemError.close();
systemError = null;
systemOut.close();
systemOut = null;
if (startTestSuiteSuccess) {
sendOutAndErr(new String(outStrm.toByteArray()),
new String(errStrm.toByteArray()));
}
}
fireEndTestSuite();
if (retCode != SUCCESS || res.errorCount() != 0) {
retCode = ERRORS;
} else if (res.failureCount() != 0) {
retCode = FAILURES;
}
}
/**
* Returns what System.exit() would return in the standalone version.
*
* @return 2 if errors occurred, 1 if tests failed else 0.
*/
public int getRetCode() {
return retCode;
}
/**
* Interface TestListener.
*
* <p>A new Test is started.
* @param t the test.
*/
public void startTest(Test t) {
String testName = JUnitVersionHelper.getTestCaseName(t);
logTestListenerEvent("startTest(" + testName + ")");
}
/**
* Interface TestListener.
*
* <p>A Test is finished.
* @param test the test.
*/
public void endTest(Test test) {
String testName = JUnitVersionHelper.getTestCaseName(test);
logTestListenerEvent("endTest(" + testName + ")");
}
private void logTestListenerEvent(String msg) {
PrintStream out = savedOut != null ? savedOut : System.out;
if (logTestListenerEvents) {
out.flush();
out.println(JUnitTask.TESTLISTENER_PREFIX + msg);
out.flush();
}
}
/**
* Interface TestListener for JUnit <= 3.4.
*
* <p>A Test failed.
* @param test the test.
* @param t the exception thrown by the test.
*/
public void addFailure(Test test, Throwable t) {
String testName = JUnitVersionHelper.getTestCaseName(test);
logTestListenerEvent("addFailure(" + testName + ", " + t.getMessage() + ")");
if (haltOnFailure) {
res.stop();
}
}
/**
* Interface TestListener for JUnit > 3.4.
*
* <p>A Test failed.
* @param test the test.
* @param t the assertion thrown by the test.
*/
public void addFailure(Test test, AssertionFailedError t) {
addFailure(test, (Throwable) t);
}
/**
* Interface TestListener.
*
* <p>An error occurred while running the test.
* @param test the test.
* @param t the error thrown by the test.
*/
public void addError(Test test, Throwable t) {
String testName = JUnitVersionHelper.getTestCaseName(test);
logTestListenerEvent("addError(" + testName + ", " + t.getMessage() + ")");
if (haltOnError) {
res.stop();
}
}
/**
* Permissions for the test run.
* @since Ant 1.6
* @param permissions the permissions to use.
*/
public void setPermissions(Permissions permissions) {
perm = permissions;
}
/**
* Handle a string destined for standard output.
* @param output the string to output
*/
public void handleOutput(String output) {
if (!logTestListenerEvents && output.startsWith(JUnitTask.TESTLISTENER_PREFIX)) {
// ignore
} else if (systemOut != null) {
systemOut.print(output);
}
}
/**
* Handle input.
* @param buffer not used.
* @param offset not used.
* @param length not used.
* @return -1 always.
* @throws IOException never.
* @see org.apache.tools.ant.Task#handleInput(byte[], int, int)
*
* @since Ant 1.6
*/
public int handleInput(byte[] buffer, int offset, int length)
throws IOException {
return -1;
}
/** {@inheritDoc}. */
public void handleErrorOutput(String output) {
if (systemError != null) {
systemError.print(output);
}
}
/** {@inheritDoc}. */
public void handleFlush(String output) {
if (systemOut != null) {
systemOut.print(output);
}
}
/** {@inheritDoc}. */
public void handleErrorFlush(String output) {
if (systemError != null) {
systemError.print(output);
}
}
private void sendOutAndErr(String out, String err) {
for (int i = 0; i < formatters.size(); i++) {
JUnitResultFormatter formatter =
((JUnitResultFormatter) formatters.elementAt(i));
formatter.setSystemOutput(out);
formatter.setSystemError(err);
}
}
private void fireStartTestSuite() {
for (int i = 0; i < formatters.size(); i++) {
((JUnitResultFormatter) formatters.elementAt(i))
.startTestSuite(junitTest);
}
}
private void fireEndTestSuite() {
for (int i = 0; i < formatters.size(); i++) {
((JUnitResultFormatter) formatters.elementAt(i))
.endTestSuite(junitTest);
}
}
/**
* Add a formatter.
* @param f the formatter to add.
*/
public void addFormatter(JUnitResultFormatter f) {
formatters.addElement(f);
}
/** {@inheritDoc}. */
public void addFormatter(JUnitTaskMirror.JUnitResultFormatterMirror f) {
formatters.addElement((JUnitResultFormatter) f);
}
/**
* Entry point for standalone (forked) mode.
*
* Parameters: testcaseclassname plus parameters in the format
* key=value, none of which is required.
*
* <table cols="4" border="1">
* <tr>key | description | default value | | haltOnError | halt test on * errors?</td> | false | * * <tr>haltOnFailure | halt test on * failures?</td> | false | * * <tr>formatter | A JUnitResultFormatter given as * classname,filename. If filename is ommitted, System.out is * assumed.</td> | none | * * <tr>showoutput | send output to System.err/.out as * well as to the formatters?</td> | false | * * <tr>logtestlistenerevents | log TestListener events to * System.out.</td> | false | * * </table> * @param args the command line arguments. * @throws IOException on error. */ public static void main(String[] args) throws IOException { boolean haltError = false; boolean haltFail = false; boolean stackfilter = true; Properties props = new Properties(); boolean showOut = false; boolean outputToFormat = true; boolean logTestListenerEvents = false; if (args.length == 0) { System.err.println("required argument TestClassName missing"); System.exit(ERRORS); } if (args[0].startsWith(Constants.TESTSFILE)) { multipleTests = true; args[0] = args[0].substring(Constants.TESTSFILE.length()); } for (int i = 1; i < args.length; i++) { if (args[i].startsWith(Constants.HALT_ON_ERROR)) { haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length())); } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) { haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length())); } else if (args[i].startsWith(Constants.FILTERTRACE)) { stackfilter = Project.toBoolean(args[i].substring(Constants.FILTERTRACE.length())); } else if (args[i].startsWith(Constants.CRASHFILE)) { crashFile = args[i].substring(Constants.CRASHFILE.length()); registerTestCase(Constants.BEFORE_FIRST_TEST); } else if (args[i].startsWith(Constants.FORMATTER)) { try { createAndStoreFormatter(args[i].substring(Constants.FORMATTER.length())); } catch (BuildException be) { System.err.println(be.getMessage()); System.exit(ERRORS); } } else if (args[i].startsWith(Constants.PROPSFILE)) { FileInputStream in = new FileInputStream(args[i] .substring(Constants.PROPSFILE.length())); props.load(in); in.close(); } else if (args[i].startsWith(Constants.SHOWOUTPUT)) { showOut = Project.toBoolean(args[i].substring(Constants.SHOWOUTPUT.length())); } else if (args[i].startsWith(Constants.LOGTESTLISTENEREVENTS)) { logTestListenerEvents = Project.toBoolean( args[i].substring(Constants.LOGTESTLISTENEREVENTS.length())); } else if (args[i].startsWith(Constants.OUTPUT_TO_FORMATTERS)) { outputToFormat = Project.toBoolean( args[i].substring(Constants.OUTPUT_TO_FORMATTERS.length())); } } // Add/overlay system properties on the properties from the Ant project Hashtable p = System.getProperties(); for (Enumeration e = p.keys(); e.hasMoreElements();) { Object key = e.nextElement(); props.put(key, p.get(key)); } int returnCode = SUCCESS; if (multipleTests) { try { java.io.BufferedReader reader = new java.io.BufferedReader(new java.io.FileReader(args[0])); String testCaseName; int code = 0; boolean errorOccurred = false; boolean failureOccurred = false; String line = null; while ((line = reader.readLine()) != null) { StringTokenizer st = new StringTokenizer(line, ","); testCaseName = st.nextToken(); JUnitTest t = new JUnitTest(testCaseName); t.setTodir(new File(st.nextToken())); t.setOutfile(st.nextToken()); code = launch(t, haltError, stackfilter, haltFail, showOut, outputToFormat, logTestListenerEvents, props); errorOccurred = (code == ERRORS); failureOccurred = (code != SUCCESS); if (errorOccurred || failureOccurred) { if ((errorOccurred && haltError) || (failureOccurred && haltFail)) { registerNonCrash(); System.exit(code); } else { if (code > returnCode) { returnCode = code; } System.out.println("TEST " + t.getName() + " FAILED"); } } } } catch (IOException e) { e.printStackTrace(); } } else { returnCode = launch(new JUnitTest(args[0]), haltError, stackfilter, haltFail, showOut, outputToFormat, logTestListenerEvents, props); } registerNonCrash(); System.exit(returnCode); } private static Vector fromCmdLine = new Vector(); private static void transferFormatters(JUnitTestRunner runner, JUnitTest test) { runner.addFormatter(new JUnitResultFormatter() { public void startTestSuite(JUnitTest suite) throws BuildException { } public void endTestSuite(JUnitTest suite) throws BuildException { } public void setOutput(OutputStream out) { } public void setSystemOutput(String out) { } public void setSystemError(String err) { } public void addError(Test arg0, Throwable arg1) { } public void addFailure(Test arg0, AssertionFailedError arg1) { } public void endTest(Test arg0) { } public void startTest(Test arg0) { registerTestCase(JUnitVersionHelper.getTestCaseName(arg0)); } }); for (int i = 0; i < fromCmdLine.size(); i++) { FormatterElement fe = (FormatterElement) fromCmdLine.elementAt(i); if (multipleTests && fe.getUseFile()) { File destFile = new File(test.getTodir(), test.getOutfile() + fe.getExtension()); fe.setOutfile(destFile); } runner.addFormatter((JUnitResultFormatter) fe.createFormatter()); } } /** * Line format is: formatter=<classname>(,
... this post is sponsored by my books ... | |
#1 New Release! |
FP Best Seller |
Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.
A percentage of advertising revenue from
pages under the /java/jwarehouse
URI on this website is
paid back to open source projects.