Browse Source

#34748: run individual test methods.

git-svn-id: https://svn.apache.org/repos/asf/ant/core/trunk@953761 13f79535-47bb-0310-9956-ffa450edef68
master
Jesse N. Glick 15 years ago
parent
commit
114d55869f
16 changed files with 850 additions and 21 deletions
  1. +3
    -0
      WHATSNEW
  2. +1
    -1
      build.xml
  3. +20
    -0
      docs/manual/Tasks/junit.html
  4. +1
    -1
      lib/libraries.properties
  5. +1
    -1
      lib/optional/README
  6. BIN
      lib/optional/junit-3.8.2.jar
  7. BIN
      lib/optional/junit-4.8.1.jar
  8. +1
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java
  9. +227
    -0
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java
  10. +33
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java
  11. +2
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java
  12. +2
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java
  13. +240
    -1
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java
  14. +132
    -11
      src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java
  15. +142
    -0
      src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java
  16. +45
    -3
      src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java

+ 3
- 0
WHATSNEW View File

@@ -61,6 +61,9 @@ Other changes:
overwrite attribute that is consistent with <copy>'s attribute overwrite attribute that is consistent with <copy>'s attribute
names. names.


* You can now specify a list of methods to run in a JUnit test case.
Bugzilla Report 34748.

Changes from Ant 1.8.0 TO Ant 1.8.1 Changes from Ant 1.8.0 TO Ant 1.8.1
=================================== ===================================




+ 1
- 1
build.xml View File

@@ -350,7 +350,7 @@
classname="org.apache.xalan.trace.TraceListenerEx3" classname="org.apache.xalan.trace.TraceListenerEx3"
classpathref="classpath" ignoresystemclasses="true"/> classpathref="classpath" ignoresystemclasses="true"/>
<available property="junit.present" <available property="junit.present"
classname="junit.framework.TestCase"
classname="org.junit.Test"
classpathref="classpath" ignoresystemclasses="true"/> classpathref="classpath" ignoresystemclasses="true"/>
<available property="antunit.present" <available property="antunit.present"
classname="org.apache.ant.antunit.AntUnit" classname="org.apache.ant.antunit.AntUnit"


+ 20
- 0
docs/manual/Tasks/junit.html View File

@@ -430,6 +430,26 @@ the name of the resulting class (without suffix). It defaults to <i>java-tmp-dir
<td valign="top">Name of the test class.</td> <td valign="top">Name of the test class.</td>
<td align="center">Yes</td> <td align="center">Yes</td>
</tr> </tr>
<tr>
<td valign="top">methods</td>
<td valign="top">Comma-separated list of names of test case methods to execute.
<em>Since 1.8.2</em>
<p>The <code>methods</code> attribute can be useful in the following scenarios:</p>
<ul>
<li>A test method has failed and you want to re-run the test method
to test a fix or re-run the test under the Java debugger without
having to wait for the other (possibly long running) test methods
to complete.</li>
<li>One or more test methods are running slower than expected and you
want to re-run them under a Java profiler (without the overhead
of running the profiler whilst other test methods are being
executed).</li>
</ul>
<p>If the <code>methods</code> attribute is used but no test method
is specified, then no test method from the suite will be executed.</p>
</td>
<td align="center">No; default is to run all test methods in the suite.</td>
</tr>
<tr> <tr>
<td valign="top">fork</td> <td valign="top">fork</td>
<td valign="top">Run the tests in a separate VM. <td valign="top">Run the tests in a separate VM.


+ 1
- 1
lib/libraries.properties View File

@@ -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=3.8.2
junit.version=4.8.1
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


+ 1
- 1
lib/optional/README View File

@@ -1,3 +1,3 @@
The file junit-3.8.2.jar is version 3.8.2 of JUnit, see the file LICENSE.junit.html
The file junit-4.8.1.jar is version 4.8.1 of JUnit, see the file LICENSE.junit.html
for the terms of distribution. For more information about JUnit or for the terms of distribution. For more information about JUnit or
the latest release, see <http://www.junit.org/>. the latest release, see <http://www.junit.org/>.

BIN
lib/optional/junit-3.8.2.jar View File


BIN
lib/optional/junit-4.8.1.jar View File


+ 1
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junit/Constants.java View File

@@ -23,6 +23,7 @@ package org.apache.tools.ant.taskdefs.optional.junit;
*/ */
public class Constants { public class Constants {


static final String METHOD_NAMES = "methods=";
static final String HALT_ON_ERROR = "haltOnError="; static final String HALT_ON_ERROR = "haltOnError=";
static final String HALT_ON_FAILURE = "haltOnFailure="; static final String HALT_ON_FAILURE = "haltOnFailure=";
static final String FILTERTRACE = "filtertrace="; static final String FILTERTRACE = "filtertrace=";


+ 227
- 0
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnit4TestMethodAdapter.java View File

@@ -0,0 +1,227 @@
/*
* 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.Iterator;
import java.util.List;
import junit.framework.JUnit4TestAdapterCache;
import junit.framework.Test;
import junit.framework.TestResult;
import org.junit.runner.Description;
import org.junit.runner.Request;
import org.junit.runner.Runner;
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
* and listening of events (test start, test finish, test failure).
* 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
* the given JUnit-4-style test methods and notifies the given {@code TestResult}
* object using its old (JUnit 3.8.x style) API.
*
* @author Marian Petras
*/
public class JUnit4TestMethodAdapter implements Test {

private final Class testClass;
private final String[] methodNames;
private final Runner runner;
private final Cache cache;

/**
* Creates a new adapter for the given class and a method within the class.
*
* @param testClass test class containing the method to be executed
* @param methodNames names of the test methods that are to be executed
* @exception java.lang.IllegalArgumentException
* if any of the arguments is {@code null}
* or if any of the given method names is {@code null} or empty
*/
public JUnit4TestMethodAdapter(final Class testClass,
final String[] methodNames) {
if (testClass == null) {
throw new IllegalArgumentException("testClass is <null>");
}
if (methodNames == null) {
throw new IllegalArgumentException("methodNames is <null>");
}
for (int i = 0; i < methodNames.length; i++) {
if (methodNames[i] == null) {
throw new IllegalArgumentException("method name #" + i + " is <null>");
}
if (methodNames[i].length() == 0) {
throw new IllegalArgumentException("method name #" + i + " is empty");
}
}
this.testClass = testClass;
this.methodNames = methodNames;
this.cache = Cache.instance;

// Warning: If 'testClass' is an old-style (pre-JUnit-4) class,
// then all its test methods will be executed by the returned runner!
Request request;
if (methodNames.length == 1) {
request = Request.method(testClass, methodNames[0]);
} else {
request = Request.aClass(testClass).filterWith(
new MultipleMethodsFilter(testClass, methodNames));
}
runner = request.getRunner();
}

public int countTestCases() {
return runner.testCount();
}

public Description getDescription() {
return runner.getDescription();
}

public List/*<Test>*/ getTests() {
return cache.asTestList(getDescription());
}

public Class getTestClass() {
return testClass;
}
public void run(final TestResult result) {
runner.run(cache.getNotifier(result));
}

public String toString() {
String testClassName = testClass.getName();
StringBuilder buf = new StringBuilder(testClassName.length()
+ 12 * methodNames.length)
.append(':');
if (methodNames.length != 0) {
buf.append(methodNames[0]);
for (int i = 1; i < methodNames.length; i++) {
buf.append(',')
.append(methodNames[i]);
}
}
return buf.toString();
}

private static final class MultipleMethodsFilter extends Filter {

private final Description methodsListDescription;
private final Class testClass;
private final String[] methodNames;

private MultipleMethodsFilter(Class testClass, String[] methodNames) {
if (testClass == null) {
throw new IllegalArgumentException("testClass is <null>");
}
if (methodNames == null) {
throw new IllegalArgumentException("methodNames is <null>");
}
methodsListDescription = Description.createSuiteDescription(testClass);
for (int i = 0; i < methodNames.length; i++) {
methodsListDescription.addChild(
Description.createTestDescription(testClass, methodNames[i]));
}
this.testClass = testClass;
this.methodNames = methodNames;
}

public boolean shouldRun(Description description) {
if (methodNames.length == 0) {
return false;
}
if (description.isTest()) {
Iterator/*<Description>*/ it = methodsListDescription.getChildren().iterator();
while (it.hasNext()) {
Description methodDescription = (Description) it.next();
if (methodDescription.equals(description)) {
return true;
}
}
} else {
Iterator/*<Description>*/ it = description.getChildren().iterator();
while (it.hasNext()) {
Description each = (Description) it.next();
if (shouldRun(each)) {
return true;
}
}
}
return false;
}

public String describe() {
StringBuilder buf = new StringBuilder(40);
if (methodNames.length == 0) {
buf.append("No methods");
} else {
buf.append(methodNames.length == 1 ? "Method" : "Methods");
buf.append(' ');
buf.append(methodNames[0]);
for (int i = 1; i < methodNames.length; i++) {
buf.append(',').append(methodNames[i]);
}
}
buf.append('(').append(testClass.getName()).append(')');
return buf.toString();
}

}

/**
* 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 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;
}

}

}

+ 33
- 1
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTask.java View File

@@ -728,6 +728,7 @@ public class JUnitTask extends Task {
new SplitClassLoader(myLoader, path, getProject(), new SplitClassLoader(myLoader, path, getProject(),
new String[] { new String[] {
"BriefJUnitResultFormatter", "BriefJUnitResultFormatter",
"JUnit4TestMethodAdapter",
"JUnitResultFormatter", "JUnitResultFormatter",
"JUnitTaskMirrorImpl", "JUnitTaskMirrorImpl",
"JUnitTestRunner", "JUnitTestRunner",
@@ -751,6 +752,8 @@ public class JUnitTask extends Task {
* @since Ant 1.2 * @since Ant 1.2
*/ */
public void execute() throws BuildException { public void execute() throws BuildException {
checkMethodLists();

setupJUnitDelegate(); setupJUnitDelegate();


List testLists = new ArrayList(); List testLists = new ArrayList();
@@ -851,6 +854,9 @@ public class JUnitTask extends Task {
while (iter.hasNext()) { while (iter.hasNext()) {
test = (JUnitTest) iter.next(); test = (JUnitTest) iter.next();
printDual(writer, logWriter, test.getName()); printDual(writer, logWriter, test.getName());
if (test.getMethods() != null) {
printDual(writer, logWriter, ":" + test.getMethodsString().replace(',', '+'));
}
if (test.getTodir() == null) { if (test.getTodir() == null) {
printDual(writer, logWriter, printDual(writer, logWriter,
"," + getProject().resolveFile(".")); "," + getProject().resolveFile("."));
@@ -922,6 +928,9 @@ public class JUnitTask extends Task {
cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner"); cmd.setClassname("org.apache.tools.ant.taskdefs.optional.junit.JUnitTestRunner");
if (casesFile == null) { if (casesFile == null) {
cmd.createArgument().setValue(test.getName()); cmd.createArgument().setValue(test.getName());
if (test.getMethods() != null) {
cmd.createArgument().setValue(Constants.METHOD_NAMES + test.getMethodsString());
}
} else { } else {
log("Running multiple tests in the same VM", Project.MSG_VERBOSE); log("Running multiple tests in the same VM", Project.MSG_VERBOSE);
cmd.createArgument().setValue(Constants.TESTSFILE + casesFile); cmd.createArgument().setValue(Constants.TESTSFILE + casesFile);
@@ -1322,7 +1331,7 @@ public class JUnitTask extends Task {
if (classLoader != null) { if (classLoader != null) {
classLoader.setThreadContextLoader(); classLoader.setThreadContextLoader();
} }
runner = delegate.newJUnitTestRunner(test, test.getHaltonerror(),
runner = delegate.newJUnitTestRunner(test, test.getMethods(), test.getHaltonerror(),
test.getFiltertrace(), test.getFiltertrace(),
test.getHaltonfailure(), false, test.getHaltonfailure(), false,
true, classLoader); true, classLoader);
@@ -1407,6 +1416,29 @@ public class JUnitTask extends Task {
return Enumerations.fromCompound(enums); return Enumerations.fromCompound(enums);
} }


/**
* Verifies all <code>test</code> elements having the <code>methods</code>
* attribute specified and having the <code>if</code>-condition resolved
* to true, that the value of the <code>methods</code> attribute is valid.
* @exception BuildException if some of the tests matching the described
* conditions has invalid value of the
* <code>methods</code> attribute
* @since 1.8.2
*/
private void checkMethodLists() throws BuildException {
if (tests.isEmpty()) {
return;
}

Enumeration testsEnum = tests.elements();
while (testsEnum.hasMoreElements()) {
JUnitTest test = (JUnitTest) testsEnum.nextElement();
if (test.hasMethodsSpecified() && test.shouldRun(getProject())) {
test.resolveMethods();
}
}
}

/** /**
* return an enumeration listing each test, then each batchtest * return an enumeration listing each test, then each batchtest
* @return enumeration * @return enumeration


+ 2
- 1
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirror.java View File

@@ -55,6 +55,7 @@ public interface JUnitTaskMirror {
/** /**
* Create a new test runner for a test. * Create a new test runner for a test.
* @param test the test to run. * @param test the test to run.
* @param methods names of the test methods to be run.
* @param haltOnError if true halt the tests if an error occurs. * @param haltOnError if true halt the tests if an error occurs.
* @param filterTrace if true filter the stack traces. * @param filterTrace if true filter the stack traces.
* @param haltOnFailure if true halt the test if a failure occurs. * @param haltOnFailure if true halt the test if a failure occurs.
@@ -63,7 +64,7 @@ public interface JUnitTaskMirror {
* @param classLoader the classloader to use to create the runner. * @param classLoader the classloader to use to create the runner.
* @return the test runner. * @return the test runner.
*/ */
JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, boolean haltOnError,
JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
boolean filterTrace, boolean haltOnFailure, boolean showOutput, boolean filterTrace, boolean haltOnFailure, boolean showOutput,
boolean logTestListenerEvents, AntClassLoader classLoader); boolean logTestListenerEvents, AntClassLoader classLoader);




+ 2
- 1
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTaskMirrorImpl.java View File

@@ -60,9 +60,10 @@ public final class JUnitTaskMirrorImpl implements JUnitTaskMirror {


/** {@inheritDoc}. */ /** {@inheritDoc}. */
public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test, public JUnitTaskMirror.JUnitTestRunnerMirror newJUnitTestRunner(JUnitTest test,
String[] methods,
boolean haltOnError, boolean filterTrace, boolean haltOnFailure, boolean haltOnError, boolean filterTrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) { boolean showOutput, boolean logTestListenerEvents, AntClassLoader classLoader) {
return new JUnitTestRunner(test, haltOnError, filterTrace, haltOnFailure,
return new JUnitTestRunner(test, methods, haltOnError, filterTrace, haltOnFailure,
showOutput, logTestListenerEvents, classLoader); showOutput, logTestListenerEvents, classLoader);
} }




+ 240
- 1
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTest.java View File

@@ -22,6 +22,7 @@ import java.util.Enumeration;
import java.util.Hashtable; import java.util.Hashtable;
import java.util.Properties; import java.util.Properties;
import java.util.Vector; import java.util.Vector;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project; import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper; import org.apache.tools.ant.PropertyHelper;


@@ -41,6 +42,19 @@ public class JUnitTest extends BaseTest implements Cloneable {
/** the name of the test case */ /** the name of the test case */
private String name = null; private String name = null;


/**
* whether the list of test methods has been specified
* @see #setMethods(java.lang.String)
* @see #setMethods(java.lang.String[])
*/
private boolean methodsSpecified = false;

/** comma-separated list of names of test methods to execute */
private String methodsList = null;

/** the names of test methods to execute */
private String[] methods = null;
/** the name of the result file */ /** the name of the result file */
private String outfile = null; private String outfile = null;


@@ -73,11 +87,53 @@ public class JUnitTest extends BaseTest implements Cloneable {
* @param filtertrace if true filter stack traces. * @param filtertrace if true filter stack traces.
*/ */
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure, public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
boolean filtertrace) {
boolean filtertrace) {
this(name, haltOnError, haltOnFailure, filtertrace, null);
}
/**
* Constructor with options.
* @param name the name of the test.
* @param haltOnError if true halt the tests if there is an error.
* @param haltOnFailure if true halt the tests if there is a failure.
* @param filtertrace if true filter stack traces.
* @param methods if true run only test methods that failed during the
* previous run of the test suite
* @since 1.8.2
*/
public JUnitTest(String name, boolean haltOnError, boolean haltOnFailure,
boolean filtertrace, String[] methods) {
this.name = name; this.name = name;
this.haltOnError = haltOnError; this.haltOnError = haltOnError;
this.haltOnFail = haltOnFailure; this.haltOnFail = haltOnFailure;
this.filtertrace = filtertrace; this.filtertrace = filtertrace;
this.methods = methods;
this.methodsSpecified = (methods != null);
}

/**
* Sets names of individual test methods to be executed.
* @param value comma-separated list of names of individual test methods
* to be executed,
* or <code>null</code> if all test methods should be executed
* @since 1.8.2
*/
public void setMethods(String value) {
methodsList = value;
methodsSpecified = (value != null);
methods = null;
}

/**
* Sets names of individual test methods to be executed.
* @param value non-empty array of names of test methods to be executed
* @see #setMethods(String)
* @since 1.8.2
*/
void setMethods(String[] value) {
methods = value;
methodsSpecified = (value != null);
methodsList = null;
} }


/** /**
@@ -96,6 +152,189 @@ public class JUnitTest extends BaseTest implements Cloneable {
outfile = value; outfile = value;
} }


/**
* Informs whether a list of test methods has been specified in this test.
* @return <code>true</code> if test methods to be executed have been
* specified, <code>false</code> otherwise
* @see #setMethods(java.lang.String)
* @see #setMethods(java.lang.String[])
* @since 1.8.2
*/
boolean hasMethodsSpecified() {
return methodsSpecified;
}

/**
* Get names of individual test methods to be executed.
*
* @return array of names of the individual test methods to be executed,
* or <code>null</code> if all test methods in the suite
* defined by the test class will be executed
* @since 1.8.2
*/
String[] getMethods() {
if (methodsSpecified && (methods == null)) {
resolveMethods();
}
return methods;
}

/**
* Gets a comma-separated list of names of methods that are to be executed
* by this test.
* @return the comma-separated list of test method names, or an empty
* string of no method is to be executed, or <code>null</code>
* if no method is specified
* @since 1.8.2
*/
String getMethodsString() {
if ((methodsList == null) && methodsSpecified) {
if (methods.length == 0) {
methodsList = "";
} else if (methods.length == 1) {
methodsList = methods[0];
} else {
StringBuffer buf = new StringBuffer(methods.length * 16);
buf.append(methods[0]);
for (int i = 1; i < methods.length; i++) {
buf.append(',').append(methods[i]);
}
methodsList = buf.toString();
}
}
return methodsList;
}

/**
* Computes the value of the {@link #methods} field from the value
* of the {@link #methodsList} field, if it has not been computed yet.
* @exception BuildException if the value of the {@link #methodsList} field
* was invalid
* @since 1.8.2
*/
void resolveMethods() {
if ((methods == null) && methodsSpecified) {
try {
methods = parseTestMethodNamesList(methodsList);
} catch (IllegalArgumentException ex) {
throw new BuildException(
"Invalid specification of test methods: \""
+ methodsList
+ "\"; expected: comma-separated list of valid Java identifiers",
ex);
}
}
}

/**
* Parses a comma-separated list of method names and check their validity.
* @param methodNames comma-separated list of method names to be parsed
* @return array of individual test method names
* @exception java.lang.IllegalArgumentException
* if the given string is <code>null</code> or if it is not
* a comma-separated list of valid Java identifiers;
* an empty string is acceptable and is handled as an empty
* list
* @since 1.8.2
*/
public static String[] parseTestMethodNamesList(String methodNames)
throws IllegalArgumentException {
if (methodNames == null) {
throw new IllegalArgumentException("methodNames is <null>");
}

methodNames = methodNames.trim();

int length = methodNames.length();
if (length == 0) {
return new String[0];
}

/* strip the trailing comma, if any */
if (methodNames.charAt(length - 1) == ',') {
methodNames = methodNames.substring(0, length - 1).trim();
length = methodNames.length();
if (length == 0) {
throw new IllegalArgumentException("Empty method name");
}
}

final char[] chars = methodNames.toCharArray();
/* easy detection of one particular case of illegal string: */
if (chars[0] == ',') {
throw new IllegalArgumentException("Empty method name");
}
/* count number of method names: */
int wordCount = 1;
for (int i = 1; i < chars.length; i++) {
if (chars[i] == ',') {
wordCount++;
}
}
/* prepare the resulting array: */
String[] result = new String[wordCount];
/* parse the string: */
final int stateBeforeWord = 1;
final int stateInsideWord = 2;
final int stateAfterWord = 3;
//
int state = stateBeforeWord;
int wordStartIndex = -1;
int wordIndex = 0;
for (int i = 0; i < chars.length; i++) {
char c = chars[i];
switch (state) {
case stateBeforeWord:
if (c == ',') {
throw new IllegalArgumentException("Empty method name");
} else if (c == ' ') {
// remain in the same state
} else if (Character.isJavaIdentifierStart(c)) {
wordStartIndex = i;
state = stateInsideWord;
} else {
throw new IllegalArgumentException("Illegal start of method name: " + c);
}
break;
case stateInsideWord:
if (c == ',') {
result[wordIndex++] = new String(methodNames.substring(wordStartIndex, i));
state = stateBeforeWord;
} else if (c == ' ') {
result[wordIndex++] = new String(methodNames.substring(wordStartIndex, i));
state = stateAfterWord;
} else if (Character.isJavaIdentifierPart(c)) {
// remain in the same state
} else {
throw new IllegalArgumentException("Illegal character in method name: " + c);
}
break;
case stateAfterWord:
if (c == ',') {
state = stateBeforeWord;
} else if (c == ' ') {
// remain in the same state
} else {
throw new IllegalArgumentException("Space in method name");
}
break;
default:
// this should never happen
}
}
switch (state) {
case stateBeforeWord:
case stateAfterWord:
break;
case stateInsideWord:
result[wordIndex++] = new String(methodNames.substring(wordStartIndex, chars.length));
break;
default:
// this should never happen
}
return result;
}

/** /**
* Get the name of the test class. * Get the name of the test class.
* @return the name of the test. * @return the name of the test.


+ 132
- 11
src/main/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunner.java View File

@@ -163,6 +163,9 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
*/ */
private static String crashFile = null; private static String crashFile = null;


/** Names of test methods to execute */
private String[] methods = null;
/** /**
* Constructor for fork=true or when the user hasn't specified a * Constructor for fork=true or when the user hasn't specified a
* classpath. * classpath.
@@ -205,7 +208,26 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
public JUnitTestRunner(JUnitTest test, boolean haltOnError, public JUnitTestRunner(JUnitTest test, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure, boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents) { boolean showOutput, boolean logTestListenerEvents) {
this(test, haltOnError, filtertrace, haltOnFailure, showOutput,
this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
logTestListenerEvents, null);
}

/**
* Constructor for fork=true or when the user hasn't specified a
* classpath.
* @param test the test to run.
* @param methods names of methods of the test to be executed.
* @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 1.8.2
*/
public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents) {
this(test, methods, haltOnError, filtertrace, haltOnFailure, showOutput,
logTestListenerEvents, null); logTestListenerEvents, null);
} }


@@ -254,12 +276,26 @@ 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) {
this(test, null, haltOnError, filtertrace, haltOnFailure, showOutput,
logTestListenerEvents, loader);
}


/**
* Constructor to use when the user has specified a classpath.
* @since 1.8.2
*/
public JUnitTestRunner(JUnitTest test, String[] methods, boolean haltOnError,
boolean filtertrace, boolean haltOnFailure,
boolean showOutput, boolean logTestListenerEvents,
ClassLoader loader) {
JUnitTestRunner.filtertrace = filtertrace; JUnitTestRunner.filtertrace = filtertrace;
this.junitTest = test; this.junitTest = test;
this.haltOnError = haltOnError; this.haltOnError = haltOnError;
this.haltOnFailure = haltOnFailure; this.haltOnFailure = haltOnFailure;
this.showOutput = showOutput; this.showOutput = showOutput;
this.logTestListenerEvents = logTestListenerEvents; this.logTestListenerEvents = logTestListenerEvents;
this.methods = methods;
this.loader = loader; this.loader = loader;
} }


@@ -340,9 +376,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
loader); loader);
} }


final boolean testMethodsSpecified = (methods != null);

// check for a static suite method first, even when using // check for a static suite method first, even when using
// JUnit 4 // JUnit 4
Method suiteMethod = null; Method suiteMethod = null;
if (!testMethodsSpecified) {
try { try {
// check if there is a suite method // check if there is a suite method
suiteMethod = testClass.getMethod("suite", new Class[0]); suiteMethod = testClass.getMethod("suite", new Class[0]);
@@ -350,6 +389,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
// no appropriate suite method found. We don't report any // no appropriate suite method found. We don't report any
// error here since it might be perfectly normal. // error here since it might be perfectly normal.
} }
}


if (suiteMethod != null) { if (suiteMethod != null) {
// if there is a suite method available, then try // if there is a suite method available, then try
@@ -359,7 +399,23 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR


} else { } else {
Class junit4TestAdapterClass = null; Class junit4TestAdapterClass = null;

boolean useSingleMethodAdapter = false;

if (junit.framework.TestCase.class.isAssignableFrom(testClass)) {
// Do not use JUnit 4 API for running JUnit 3.x
// tests - it is not able to run individual test
// methods.
//
// Technical details:
// org.junit.runner.Request.method(Class, String).getRunner()
// would return a runner which always executes all
// test methods. The reason is that the Runner would be
// an instance of class
// org.junit.internal.runners.OldTestClassRunner
// that does not implement interface Filterable - so it
// is unable to filter out test methods not matching
// the requested name.
} else {
// Check for JDK 5 first. Will *not* help on JDK 1.4 // Check for JDK 5 first. Will *not* help on JDK 1.4
// if only junit-4.0.jar in CP because in that case // if only junit-4.0.jar in CP because in that case
// linkage of whole task will already have failed! But // linkage of whole task will already have failed! But
@@ -373,29 +429,69 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
if (loader == null) { if (loader == null) {
junit4TestAdapterClass = junit4TestAdapterClass =
Class.forName(JUNIT_4_TEST_ADAPTER); Class.forName(JUNIT_4_TEST_ADAPTER);
if (testMethodsSpecified) {
/*
* We cannot try to load the JUnit4TestAdapter
* before trying to load JUnit4TestMethodAdapter
* because it might fail with
* NoClassDefFoundException, instead of plain
* ClassNotFoundException.
*/
junit4TestAdapterClass = Class.forName(
"org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter");
useSingleMethodAdapter = true;
}
} else { } else {
junit4TestAdapterClass = junit4TestAdapterClass =
Class.forName(JUNIT_4_TEST_ADAPTER, Class.forName(JUNIT_4_TEST_ADAPTER,
true, loader); true, loader);
if (testMethodsSpecified) {
junit4TestAdapterClass =
Class.forName(
"org.apache.tools.ant.taskdefs.optional.junit.JUnit4TestMethodAdapter",
true, loader);
useSingleMethodAdapter = true;
}
} }
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
// OK, fall back to JUnit 3. // OK, fall back to JUnit 3.
} }
}
junit4 = junit4TestAdapterClass != null; junit4 = junit4TestAdapterClass != null;


if (junit4) { if (junit4) {
// Let's use it! // Let's use it!
Class[] formalParams;
Object[] actualParams;
if (useSingleMethodAdapter) {
formalParams = new Class[] {Class.class, String[].class};
actualParams = new Object[] {testClass, methods};
} else {
formalParams = new Class[] {Class.class};
actualParams = new Object[] {testClass};
}
suite = suite =
(Test) junit4TestAdapterClass (Test) junit4TestAdapterClass
.getConstructor(new Class[] {Class.class}).
newInstance(new Object[] {testClass});
.getConstructor(formalParams).
newInstance(actualParams);
} else { } else {
// Use JUnit 3. // Use JUnit 3.


// try to extract a test suite automatically this // try to extract a test suite automatically this
// will generate warnings if the class is no // will generate warnings if the class is no
// suitable Test // suitable Test
suite = new TestSuite(testClass);
if (!testMethodsSpecified) {
suite = new TestSuite(testClass);
} else if (methods.length == 1) {
suite = TestSuite.createTest(testClass, methods[0]);
} else {
TestSuite testSuite = new TestSuite(testClass.getName());
for (int i = 0; i < methods.length; i++) {
testSuite.addTest(
TestSuite.createTest(testClass, methods[i]));
}
suite = testSuite;
}
} }


} }
@@ -670,11 +766,16 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
* <tr><td>logtestlistenerevents</td><td>log TestListener events to * <tr><td>logtestlistenerevents</td><td>log TestListener events to
* System.out.</td><td>false</td></tr> * System.out.</td><td>false</td></tr>
* *
* <tr><td>methods</td><td>Comma-separated list of names of individual
* test methods to execute.
* </td><td>null</td></tr>
*
* </table> * </table>
* @param args the command line arguments. * @param args the command line arguments.
* @throws IOException on error. * @throws IOException on error.
*/ */
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
String[] methods = null;
boolean haltError = false; boolean haltError = false;
boolean haltFail = false; boolean haltFail = false;
boolean stackfilter = true; boolean stackfilter = true;
@@ -696,7 +797,15 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
} }


for (int i = 1; i < args.length; i++) { for (int i = 1; i < args.length; i++) {
if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
if (args[i].startsWith(Constants.METHOD_NAMES)) {
try {
String methodsList = args[i].substring(Constants.METHOD_NAMES.length());
methods = JUnitTest.parseTestMethodNamesList(methodsList);
} catch (IllegalArgumentException ex) {
System.err.println("Invalid specification of test method names: " + args[i]);
System.exit(ERRORS);
}
} else if (args[i].startsWith(Constants.HALT_ON_ERROR)) {
haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length())); haltError = Project.toBoolean(args[i].substring(Constants.HALT_ON_ERROR.length()));
} else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) { } else if (args[i].startsWith(Constants.HALT_ON_FAILURE)) {
haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length())); haltFail = Project.toBoolean(args[i].substring(Constants.HALT_ON_FAILURE.length()));
@@ -744,18 +853,30 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
java.io.BufferedReader reader = java.io.BufferedReader reader =
new java.io.BufferedReader(new java.io.FileReader(args[0])); new java.io.BufferedReader(new java.io.FileReader(args[0]));
String testCaseName; String testCaseName;
String[] testMethodNames;
int code = 0; int code = 0;
boolean errorOccurred = false; boolean errorOccurred = false;
boolean failureOccurred = false; boolean failureOccurred = false;
String line = null; String line = null;
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
StringTokenizer st = new StringTokenizer(line, ","); StringTokenizer st = new StringTokenizer(line, ",");
testCaseName = st.nextToken();
String testListSpec = st.nextToken();
int colonIndex = testListSpec.indexOf(':');
if (colonIndex == -1) {
testCaseName = testListSpec;
testMethodNames = null;
} else {
testCaseName = testListSpec.substring(0, colonIndex);
testMethodNames = JUnitTest.parseTestMethodNamesList(
testListSpec
.substring(colonIndex + 1)
.replace('+', ','));
}
JUnitTest t = new JUnitTest(testCaseName); JUnitTest t = new JUnitTest(testCaseName);
t.setTodir(new File(st.nextToken())); t.setTodir(new File(st.nextToken()));
t.setOutfile(st.nextToken()); t.setOutfile(st.nextToken());
t.setProperties(props); t.setProperties(props);
code = launch(t, haltError, stackfilter, haltFail,
code = launch(t, testMethodNames, haltError, stackfilter, haltFail,
showOut, outputToFormat, showOut, outputToFormat,
logTestListenerEvents); logTestListenerEvents);
errorOccurred = (code == ERRORS); errorOccurred = (code == ERRORS);
@@ -783,7 +904,7 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
JUnitTest t = new JUnitTest(args[0]); JUnitTest t = new JUnitTest(args[0]);
t.setProperties(props); t.setProperties(props);
returnCode = launch( returnCode = launch(
t, haltError, stackfilter, haltFail,
t, methods, haltError, stackfilter, haltFail,
showOut, outputToFormat, logTestListenerEvents); showOut, outputToFormat, logTestListenerEvents);
} }


@@ -917,12 +1038,12 @@ public class JUnitTestRunner implements TestListener, JUnitTaskMirror.JUnitTestR
/** /**
* @since Ant 1.6.2 * @since Ant 1.6.2
*/ */
private static int launch(JUnitTest t, boolean haltError,
private static int launch(JUnitTest t, String[] methods, boolean haltError,
boolean stackfilter, boolean haltFail, boolean stackfilter, boolean haltFail,
boolean showOut, boolean outputToFormat, boolean showOut, boolean outputToFormat,
boolean logTestListenerEvents) { boolean logTestListenerEvents) {
JUnitTestRunner runner = JUnitTestRunner runner =
new JUnitTestRunner(t, haltError, stackfilter, haltFail, showOut,
new JUnitTestRunner(t, methods, haltError, stackfilter, haltFail, showOut,
logTestListenerEvents, null); logTestListenerEvents, null);
runner.forked = true; runner.forked = true;
runner.outputToFormatters = outputToFormat; runner.outputToFormatters = outputToFormat;


+ 142
- 0
src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/BatchTestTest.java View File

@@ -0,0 +1,142 @@
/*
* 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.ComparisonFailure;
import junit.framework.TestCase;

/**
*
* @author Marian Petras
*/
public class BatchTestTest extends TestCase {
public BatchTestTest(String testName) {
super(testName);
}


public void testParseTestMethodNamesList() {
try {
JUnitTest.parseTestMethodNamesList(null);
fail("IllegalArgumentException expected when the param is <null>");
} catch (IllegalArgumentException ex) {
//this is an expected exception
}

assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(""));
assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(" "));
assertEquals(new String[0], JUnitTest.parseTestMethodNamesList(" "));

checkParseCausesIAE(",");
checkParseCausesIAE(" ,");
checkParseCausesIAE(", ");
checkParseCausesIAE(" , ");
checkParseCausesIAE(",a");
checkParseCausesIAE(" ,a");
checkParseCausesIAE(" ,a");
checkParseCausesIAE(" , a");
checkParseCausesIAE(" ,a ");
checkParseCausesIAE(" ,a ,");
checkParseCausesIAE("ab,,cd");
checkParseCausesIAE("ab, ,cd");
checkParseCausesIAE("ab, ,cd");
checkParseCausesIAE("ab, ,cd,");
checkParseCausesIAE(",ab, ,cd,");

assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc"));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc "));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc"));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc "));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc "));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc,"));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc, "));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc ,"));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList("abc , "));
assertEquals(new String[] {"abc"}, JUnitTest.parseTestMethodNamesList(" abc ,"));

/* legal Java identifiers: */
assertEquals(new String[] {"a"}, JUnitTest.parseTestMethodNamesList("a"));
assertEquals(new String[] {"a1"}, JUnitTest.parseTestMethodNamesList("a1"));
assertEquals(new String[] {"a$"}, JUnitTest.parseTestMethodNamesList("a$"));
assertEquals(new String[] {"a$1"}, JUnitTest.parseTestMethodNamesList("a$1"));
assertEquals(new String[] {"_bc"}, JUnitTest.parseTestMethodNamesList("_bc"));
assertEquals(new String[] {"___"}, JUnitTest.parseTestMethodNamesList("___"));

/* illegal Java identifiers: */
checkParseCausesIAE("1");
checkParseCausesIAE("1a");
checkParseCausesIAE("1ab");
checkParseCausesIAE("1abc");
checkParseCausesIAE("1abc d");
checkParseCausesIAE("1abc de");
checkParseCausesIAE("1abc def");
checkParseCausesIAE("1abc def,");
checkParseCausesIAE(",1abc def");

assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def,"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc,def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc, def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc, def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc ,def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc ,def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc , def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList("abc , def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc,def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc,def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc, def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc, def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc ,def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc ,def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def"));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def "));
assertEquals(new String[] {"abc", "def"}, JUnitTest.parseTestMethodNamesList(" abc , def ,"));
}

private static void checkParseCausesIAE(String param) {
try {
JUnitTest.parseTestMethodNamesList(param);
fail("IllegalArgumentException expected when the param is \"" + param + '"');
} catch (IllegalArgumentException ex) {
//this is an expected exception
}
}

private static void assertEquals(String[] expected, String[] actual) {
assertEquals(null, expected, actual);
}

private static void assertEquals(String message,
String[] expected,
String[] actual) {
if ((expected == null) && (actual == null)) {
return;
}
if (expected.length != actual.length) {
throw new ComparisonFailure(message,
expected.toString(),
actual.toString());
}
for (int i = 0; i < expected.length; i++) {
assertEquals(expected[i], actual[i]);
}
}

}

+ 45
- 3
src/tests/junit/org/apache/tools/ant/taskdefs/optional/junit/JUnitTestRunnerTest.java View File

@@ -33,6 +33,22 @@ public class JUnitTestRunnerTest extends TestCase {
super(name); super(name);
} }


// check that a valid method name generates no errors
public void testValidMethod(){
TestRunner runner = createRunnerForTestMethod(ValidMethodTestCase.class,"testA");
runner.run();
assertEquals(runner.getFormatter().getError(), JUnitTestRunner.SUCCESS, runner.getRetCode());
}

// check that having an invalid method name generates an error
public void testInvalidMethod(){
TestRunner runner = createRunnerForTestMethod(InvalidMethodTestCase.class,"testInvalid");
runner.run();
String error = runner.getFormatter().getError();
// might be FAILURES or ERRORS depending on JUnit version?
assertTrue(error, runner.getRetCode() != JUnitTestRunner.SUCCESS);
}
// check that having no suite generates no errors // check that having no suite generates no errors
public void testNoSuite(){ public void testNoSuite(){
TestRunner runner = createRunner(NoSuiteTestCase.class); TestRunner runner = createRunner(NoSuiteTestCase.class);
@@ -87,14 +103,22 @@ public class JUnitTestRunnerTest extends TestCase {
} }


protected TestRunner createRunner(Class clazz){ protected TestRunner createRunner(Class clazz){
return new TestRunner(new JUnitTest(clazz.getName()), true, true, true);
return new TestRunner(new JUnitTest(clazz.getName()), null,
true, true, true);
} }


protected TestRunner createRunnerForTestMethod(Class clazz, String method){
return new TestRunner(new JUnitTest(clazz.getName()), new String[] {method},
true, true, true);
}
// the test runner that wrap the dummy formatter that interests us // the test runner that wrap the dummy formatter that interests us
private final static class TestRunner extends JUnitTestRunner { private final static class TestRunner extends JUnitTestRunner {
private ResultFormatter formatter = new ResultFormatter(); private ResultFormatter formatter = new ResultFormatter();
TestRunner(JUnitTest test, boolean haltonerror, boolean filtertrace, boolean haltonfailure){
super(test, haltonerror, filtertrace, haltonfailure, TestRunner.class.getClassLoader());
TestRunner(JUnitTest test, String[] methods, boolean haltonerror,
boolean filtertrace, boolean haltonfailure){
super(test, methods, haltonerror, filtertrace, haltonfailure,
false, false, TestRunner.class.getClassLoader());
// use the classloader that loaded this class otherwise // use the classloader that loaded this class otherwise
// it will not be able to run inner classes if this test // it will not be able to run inner classes if this test
// is ran in non-forked mode. // is ran in non-forked mode.
@@ -133,6 +157,24 @@ public class JUnitTestRunnerTest extends TestCase {
public static class NoTestCase { public static class NoTestCase {
} }


public static class InvalidMethodTestCase extends TestCase {
public InvalidMethodTestCase(String name){ super(name); }
public void testA(){
throw new NullPointerException("thrown on purpose");
}
}

public static class ValidMethodTestCase extends TestCase {
public ValidMethodTestCase(String name){ super(name); }
public void testA(){
// expected to be executed
}
public void testB(){
// should not be executed
throw new NullPointerException("thrown on purpose");
}
}
public static class InvalidTestCase extends TestCase { public static class InvalidTestCase extends TestCase {
public InvalidTestCase(String name){ public InvalidTestCase(String name){
super(name); super(name);


Loading…
Cancel
Save