handle more completely junit4 suites
git-svn-id: https://svn.apache.org/repos/asf/ant/antlibs/antunit/trunk@745628 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/main/org/apache/ant/antunit/junit3/AntUnitSuite.java b/src/main/org/apache/ant/antunit/junit3/AntUnitSuite.java
index 337fe7b..8ec59bf 100644
--- a/src/main/org/apache/ant/antunit/junit3/AntUnitSuite.java
+++ b/src/main/org/apache/ant/antunit/junit3/AntUnitSuite.java
@@ -23,7 +23,6 @@
import java.io.File;
import java.io.PrintStream;
import java.util.Collections;
-import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
@@ -32,6 +31,7 @@
import junit.framework.TestResult;
import junit.framework.TestSuite;
+import org.apache.ant.antunit.AntUnitExecutionNotifier;
import org.apache.ant.antunit.AntUnitScriptRunner;
import org.apache.ant.antunit.ProjectFactory;
import org.apache.tools.ant.BuildException;
@@ -117,7 +117,9 @@
initializationReportingTest.run(testResult);
} else {
List testTartgets = antScriptRunner.getTestTartgets();
- runInContainer(testTartgets, testResult);
+ JUnitNotificationAdapter notifier = new JUnitNotificationAdapter(
+ testResult, tests());
+ runInContainer(testTartgets, notifier);
}
}
@@ -142,7 +144,9 @@
} else {
String targetName = ((AntUnitTestCase) test).getTarget();
List singleTargetList = Collections.singletonList(targetName);
- runInContainer(singleTargetList, result);
+ JUnitNotificationAdapter notifier = new JUnitNotificationAdapter(
+ result, tests());
+ runInContainer(singleTargetList, notifier);
}
}
@@ -150,18 +154,14 @@
* Execute the test suite in a 'container' similar to the ant 'container'.
* When ant executes a project it redirect the input and the output. In this
* context we will only redirect output (unit test are not supposed to be
- * interactive)
+ * interactive).<br/>
*
* @param targetList
* The list of test target to execute
- * @param result
- * The JUnit3 TestResult receiving result notification
- * @param tests
- * The JUnit3 Test classes instances to use in the notification.
+ * @param notifier
+ * The AntUnit notifier that will receive execution notifications
*/
- private void runInContainer(List targetList, TestResult result) {
- JUnitNotificationAdapter notifier = new JUnitNotificationAdapter(
- result, tests());
+ public void runInContainer(List targetList, AntUnitExecutionNotifier notifier) {
PrintStream savedErr = System.err;
PrintStream savedOut = System.out;
try {
diff --git a/src/main/org/apache/ant/antunit/junit4/AntUnitSuiteRunner.java b/src/main/org/apache/ant/antunit/junit4/AntUnitSuiteRunner.java
index 5f7e597..4d974e0 100644
--- a/src/main/org/apache/ant/antunit/junit4/AntUnitSuiteRunner.java
+++ b/src/main/org/apache/ant/antunit/junit4/AntUnitSuiteRunner.java
@@ -20,35 +20,62 @@
package org.apache.ant.antunit.junit4;
+import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import org.apache.ant.antunit.AntUnitExecutionNotifier;
+import org.apache.ant.antunit.AssertionFailedException;
import org.apache.ant.antunit.junit3.AntUnitSuite;
import org.apache.ant.antunit.junit3.AntUnitTestCase;
-import org.junit.internal.runners.CompositeRunner;
import org.junit.internal.runners.InitializationError;
+import org.junit.runner.Description;
+import org.junit.runner.Runner;
+import org.junit.runner.manipulation.Filter;
+import org.junit.runner.manipulation.Filterable;
+import org.junit.runner.manipulation.NoTestsRemainException;
+import org.junit.runner.manipulation.Sortable;
+import org.junit.runner.manipulation.Sorter;
+import org.junit.runner.notification.Failure;
+import org.junit.runner.notification.RunNotifier;
/**
* JUnit4 Runner to put in a RunWith annotation of the AntUnitSuite when using a
* JUnit4 runner. Using this runner is not mandatory because junit4 is able to
- * run junit3 test. However, the test will be faster (TODO make that true :-) )
- * with this Runner. Also, more features are available when this runner is used
- * (filtering & sorting)
- * TODO Support filtering and sorting
+ * run junit3 test. However, the test may be faster with this Runner (with the
+ * default junit4 adapter, the suiteSetUp and suiteTearDown will be executed
+ * around every test target). Also, more features are available when this runner
+ * is used (filtering & sorting)
*/
-public class AntUnitSuiteRunner extends CompositeRunner {
+public class AntUnitSuiteRunner extends Runner implements Filterable, Sortable {
+ private final AntUnitSuite junit3Suite;
+ private final Map/*<String, Description>*/ targetDescriptions = new HashMap();
+ private final List/*<String>*/ targetsOrder = new LinkedList();
+
private AntUnitSuiteRunner(AntUnitSuite suite, Class junitTestClass) {
- super(suite.getName());
+ junit3Suite = suite;
Enumeration tests = suite.tests();
while (tests.hasMoreElements()) {
//TODO Handle the the case of FileNotFound.
//In that case the suite contains an error Test and we have
- //a ClassCastException instead of a nice & clear error
+ //a ClassCastException instead of a nice & clear error
+ //TODO Handle the possibility for the user to define suite of AntUnit scripts
AntUnitTestCase tc = (AntUnitTestCase) tests.nextElement();
- add(new AntUnitTestCaseRunner(tc, junitTestClass));
+ Description tc_desc = Description.createTestDescription(junitTestClass, tc.getName());
+ targetDescriptions.put(tc.getTarget(), tc_desc);
+ targetsOrder.add(tc.getTarget());
}
}
@@ -63,16 +90,93 @@
if (!Modifier.isStatic(suiteMethod.getModifiers())) {
throw new InitializationError("suite method must be static");
}
- return (AntUnitSuite) suiteMethod.invoke(null, new Object[0]);
+ Object suite = suiteMethod.invoke(null, new Object[0]);
+ if (suite == null) {
+ throw new InitializationError("suite method can not return null");
+ }
+ if (!(suite instanceof AntUnitSuite)) {
+ throw new InitializationError("suite method must return an AntUnitSuite");
+ }
+ return (AntUnitSuite) suite;
} catch (NoSuchMethodException e) {
throw new InitializationError(new Throwable[] { e });
} catch (IllegalAccessException e) {
throw new InitializationError(new Throwable[] { e });
} catch (InvocationTargetException e) {
throw new InitializationError(new Throwable[] { e });
- } catch (ClassCastException e) {
- throw new InitializationError(new Throwable[] { e });
}
}
+ /**
+ * @Overwrite Filterable implementation
+ */
+ public void filter(Filter filter) throws NoTestsRemainException {
+ for (Iterator iter= targetDescriptions.entrySet().iterator(); iter.hasNext();) {
+ Map.Entry mapEntry = (Entry) iter.next();
+ if (!filter.shouldRun((Description) mapEntry.getValue()))
+ iter.remove();
+ targetsOrder.remove(mapEntry.getKey());
+ }
+ }
+
+ /**
+ * @Overwrite Sortable implementation
+ */
+ public void sort(final Sorter sorter) {
+ Collections.sort(targetsOrder, new Comparator/*<String>*/() {
+ public int compare(Object target1, Object target2) {
+ Description d2 = (Description)targetDescriptions.get(target2);
+ Description d1 = (Description)targetDescriptions.get(target1);
+ return sorter.compare(d1, d2);
+ }
+ });
+ /*for (Runner each : fRunners)
+ sorter.apply(each);
+ */
+ }
+
+ /**
+ * @Overwrite Runner implementation
+ */
+ public Description getDescription() {
+ Description r = Description.createSuiteDescription(
+ junit3Suite.getName(), new Annotation[0]);
+
+ Collection childDesc = targetDescriptions.values();
+ for (Iterator iterator = childDesc.iterator(); iterator.hasNext();) {
+ Description desc = (Description) iterator.next();
+ r.addChild(desc);
+ }
+ return r;
+ }
+
+ /**
+ * @Overwrite Runner implementation
+ */
+ public void run(final RunNotifier junitNotifier) {
+ LinkedList targetList = new LinkedList(targetDescriptions.keySet());
+
+ AntUnitExecutionNotifier antUnitNotifier = new AntUnitExecutionNotifier() {
+ public void fireStartTest(String targetName) {
+ junitNotifier.fireTestStarted(getDescription(targetName));
+ }
+ public void fireEndTest(String targetName) {
+ junitNotifier.fireTestFinished(getDescription(targetName));
+ }
+ public void fireError(String targetName, Throwable t) {
+ Failure failure = new Failure(getDescription(targetName), t);
+ junitNotifier.fireTestFailure(failure);
+ }
+ public void fireFail(String targetName, AssertionFailedException ae) {
+ Failure failure = new Failure(getDescription(targetName), ae);
+ junitNotifier.fireTestFailure(failure);
+ }
+ private Description getDescription(String targetName) {
+ return (Description) targetDescriptions.get(targetName);
+ }
+ };
+
+ junit3Suite.runInContainer(targetList, antUnitNotifier);
+ }
+
}
diff --git a/src/main/org/apache/ant/antunit/junit4/AntUnitTestCaseRunner.java b/src/main/org/apache/ant/antunit/junit4/AntUnitTestCaseRunner.java
deleted file mode 100644
index a494190..0000000
--- a/src/main/org/apache/ant/antunit/junit4/AntUnitTestCaseRunner.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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.ant.antunit.junit4;
-
-import junit.framework.AssertionFailedError;
-import junit.framework.Test;
-import junit.framework.TestListener;
-import junit.framework.TestResult;
-
-import org.apache.ant.antunit.junit3.AntUnitTestCase;
-import org.junit.runner.Description;
-import org.junit.runner.Runner;
-import org.junit.runner.notification.Failure;
-import org.junit.runner.notification.RunNotifier;
-
-
-class AntUnitTestCaseRunner extends Runner {
-
- private final AntUnitTestCase fTest;
- private final Class junitTestClass;
-
- public AntUnitTestCaseRunner(AntUnitTestCase testCase, Class junitTestClass) {
- this.fTest = testCase;
- this.junitTestClass = junitTestClass;
- }
-
- public void run(final RunNotifier notifier) {
- final Description description = getDescription();
- TestListener testListener = new TestListener() {
- // TODO implement directly the mapping from AntUnitExecutionNotifier
- // to junit4 RunNotifier
- public void endTest(Test test) {
- notifier.fireTestFinished(description);
- }
-
- public void startTest(Test test) {
- notifier.fireTestStarted(description);
- }
-
- public void addError(Test test, Throwable t) {
- Failure failure = new Failure(description, t);
- notifier.fireTestFailure(failure);
- }
-
- public void addFailure(Test test, AssertionFailedError t) {
- addError(test, t);
- }
- };
- TestResult result = new TestResult();
- result.addListener(testListener);
- fTest.run(result);
- }
-
- public Description getDescription() {
- return Description.createTestDescription(junitTestClass, fTest
- .getName());
- }
-
-}
diff --git a/src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteTest.java b/src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteRunnerTest.java
similarity index 66%
rename from src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteTest.java
rename to src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteRunnerTest.java
index 9be7f35..f827e21 100644
--- a/src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteTest.java
+++ b/src/tests/junit/org/apache/ant/antunit/junit4/AntUnitSuiteRunnerTest.java
@@ -20,22 +20,45 @@
package org.apache.ant.antunit.junit4;
import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.IOException;
import java.util.ArrayList;
import junit.framework.TestCase;
+import junit.framework.TestSuite;
import org.apache.ant.antunit.junit3.AntUnitSuite;
-import org.junit.Ignore;
+import org.apache.tools.ant.util.FileUtils;
import org.junit.internal.runners.InitializationError;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
-public class AntUnitSuiteTest extends TestCase {
+public class AntUnitSuiteRunnerTest extends TestCase {
private boolean mockExecutionOK = false;
private String mockExcutionError = "";
/**
+ * Validates the execution sequence.
+ */
+ public void testRunFullSuite() throws FileNotFoundException, IOException,
+ InitializationError {
+ AntUnitSuiteRunner runner = new AntUnitSuiteRunner(
+ JUnit4AntUnitRunnable.class);
+
+ runner.run(new RunNotifier());
+ File outFile = new File("target/test_output/junit_out.xml");
+
+ String output = FileUtils.readFully(new FileReader(outFile));
+ String EXPECT1 = "suiteSetUp-setUp-test1-tearDown-setUp-test2-tearDown-suiteTearDown";
+ String EXPECT2 = "suiteSetUp-setUp-test2-tearDown-setUp-test1-tearDown-suiteTearDown";
+ assertTrue("unexted output : " + output, EXPECT1.equals(output)
+ || EXPECT2.equals(output));
+ }
+
+
+ /**
* When a test is executed, the description used in the notification must be
* equals to the description declared, otherwise the runner is confused (for
* example in eclipse you have all the tests listed twice, but reported only
@@ -108,6 +131,31 @@
}
}
+ public void testInvalidSuiteReturnTypeError() {
+ try {
+ AntUnitSuiteRunner runner = new AntUnitSuiteRunner(
+ JUnit4AntUnitRunnableWithInvalidSuiteReturnType.class);
+ fail("InitializationError expected");
+ } catch (InitializationError e) {
+ String msg = e.getCauses().get(0).getMessage();
+ assertTrue("Unexpected error : " + msg, msg.contains("suite"));
+ assertTrue("Unexpected error : " + msg, msg.contains("AntUnitSuite"));
+ }
+ }
+
+ public void testInvalidSuiteReturnNull() {
+ try {
+ AntUnitSuiteRunner runner = new AntUnitSuiteRunner(
+ JUnit4AntUnitRunnableWithInvalidSuiteReturningNull.class);
+ fail("InitializationError expected");
+ } catch (InitializationError e) {
+ String msg = e.getCauses().get(0).getMessage();
+ assertTrue("Unexpected error : " + msg, msg.contains("suite"));
+ assertTrue("Unexpected error : " + msg, msg.contains("null"));
+ }
+ }
+
+
public static class JUnit4AntUnitRunnable {
public static AntUnitSuite suite() {
File f = new File("src/etc/testcases/antunit/junit.xml");
@@ -126,4 +174,17 @@
public static class JUnit4AntUnitRunnableWithoutSuiteMethod {
}
+ public static class JUnit4AntUnitRunnableWithInvalidSuiteReturnType {
+ public static TestSuite suite() {
+ return new TestSuite("We don't support returning generic TestSuite." +
+ " The Runner can not handle that");
+ }
+ }
+
+ public static class JUnit4AntUnitRunnableWithInvalidSuiteReturningNull {
+ public static TestSuite suite() {
+ return null;
+ }
+ }
+
}