diff options
Diffstat (limited to 'dx/src/junit/framework/TestSuite.java')
-rw-r--r-- | dx/src/junit/framework/TestSuite.java | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/dx/src/junit/framework/TestSuite.java b/dx/src/junit/framework/TestSuite.java new file mode 100644 index 0000000..2987ad1 --- /dev/null +++ b/dx/src/junit/framework/TestSuite.java @@ -0,0 +1,265 @@ +package junit.framework; + +import java.util.Vector; +import java.util.Enumeration; +import java.io.PrintWriter;import java.io.StringWriter;import java.lang.reflect.*; +import java.lang.reflect.Constructor; + +/** + * A <code>TestSuite</code> is a <code>Composite</code> of Tests. + * It runs a collection of test cases. Here is an example using + * the dynamic test definition. + * <pre> + * TestSuite suite= new TestSuite(); + * suite.addTest(new MathTest("testAdd")); + * suite.addTest(new MathTest("testDivideByZero")); + * </pre> + * Alternatively, a TestSuite can extract the tests to be run automatically. + * To do so you pass the class of your TestCase class to the + * TestSuite constructor. + * <pre> + * TestSuite suite= new TestSuite(MathTest.class); + * </pre> + * This constructor creates a suite with all the methods + * starting with "test" that take no arguments. + * + * @see Test + */ +public class TestSuite implements Test { + + private Vector<Test> fTests= new Vector<Test>(10); + private String fName; + + /** + * Constructs an empty TestSuite. + */ + public TestSuite() { + } + + /** + * Constructs a TestSuite from the given class with the given name. + * @see TestSuite#TestSuite(Class) + */ + public TestSuite(Class theClass, String name) { + this(theClass); + setName(name); + } + + /** + * Constructs a TestSuite from the given class. Adds all the methods + * starting with "test" as test cases to the suite. + * Parts of this method was written at 2337 meters in the Huffihutte, + * Kanton Uri + */ + public TestSuite(final Class theClass) { + fName= theClass.getName(); + try { + getTestConstructor(theClass); // Avoid generating multiple error messages + } catch (NoSuchMethodException e) { + addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); + return; + } + + if (!Modifier.isPublic(theClass.getModifiers())) { + addTest(warning("Class "+theClass.getName()+" is not public")); + return; + } + + Class superClass= theClass; + Vector<String> names= new Vector<String>(); + while (Test.class.isAssignableFrom(superClass)) { + Method[] methods= superClass.getDeclaredMethods(); + for (int i= 0; i < methods.length; i++) { + addTestMethod(methods[i], names, theClass); + } + superClass= superClass.getSuperclass(); + } + if (fTests.size() == 0) + addTest(warning("No tests found in "+theClass.getName())); + } + + /** + * Constructs an empty TestSuite. + */ + public TestSuite(String name) { + setName(name); + } + + /** + * Adds a test to the suite. + */ + public void addTest(Test test) { + fTests.addElement(test); + } + + /** + * Adds the tests from the given class to the suite + */ + public void addTestSuite(Class testClass) { + addTest(new TestSuite(testClass)); + } + + private void addTestMethod(Method m, Vector<String> names, Class theClass) { + String name= m.getName(); + if (names.contains(name)) + return; + if (! isPublicTestMethod(m)) { + if (isTestMethod(m)) + addTest(warning("Test method isn't public: "+m.getName())); + return; + } + names.addElement(name); + addTest(createTest(theClass, name)); + } + + /** + * ...as the moon sets over the early morning Merlin, Oregon + * mountains, our intrepid adventurers type... + */ + static public Test createTest(Class theClass, String name) { + Constructor constructor; + try { + constructor= getTestConstructor(theClass); + } catch (NoSuchMethodException e) { + return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"); + } + Object test; + try { + if (constructor.getParameterTypes().length == 0) { + test= constructor.newInstance(new Object[0]); + if (test instanceof TestCase) + ((TestCase) test).setName(name); + } else { + test= constructor.newInstance(new Object[]{name}); + } + } catch (InstantiationException e) { + return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")")); + } catch (InvocationTargetException e) { + return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")")); + } catch (IllegalAccessException e) { + return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")")); + } + return (Test) test; + } + + /** + * Converts the stack trace into a string + */ + private static String exceptionToString(Throwable t) { + StringWriter stringWriter= new StringWriter(); + PrintWriter writer= new PrintWriter(stringWriter); + t.printStackTrace(writer); + return stringWriter.toString(); + + } + + /** + * Counts the number of test cases that will be run by this test. + */ + public int countTestCases() { + int count= 0; + for (Enumeration e= tests(); e.hasMoreElements(); ) { + Test test= (Test)e.nextElement(); + count= count + test.countTestCases(); + } + return count; + } + + /** + * Gets a constructor which takes a single String as + * its argument or a no arg constructor. + */ + public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { + Class[] args= { String.class }; + try { + return theClass.getConstructor(args); + } catch (NoSuchMethodException e) { + // fall through + } + return theClass.getConstructor(new Class[0]); + } + + private boolean isPublicTestMethod(Method m) { + return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); + } + + private boolean isTestMethod(Method m) { + String name= m.getName(); + Class[] parameters= m.getParameterTypes(); + Class returnType= m.getReturnType(); + return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); + } + + /** + * Runs the tests and collects their result in a TestResult. + */ + public void run(TestResult result) { + for (Enumeration e= tests(); e.hasMoreElements(); ) { + if (result.shouldStop() ) + break; + Test test= (Test)e.nextElement(); + runTest(test, result); + } + } + + public void runTest(Test test, TestResult result) { + test.run(result); + } + + /** + * Returns the test at the given index + */ + public Test testAt(int index) { + return (Test)fTests.elementAt(index); + } + + /** + * Returns the number of tests in this suite + */ + public int testCount() { + return fTests.size(); + } + + /** + * Returns the tests as an enumeration + */ + public Enumeration tests() { + return fTests.elements(); + } + + /** + */ + public String toString() { + if (getName() != null) + return getName(); + return super.toString(); + } + + /** + * Sets the name of the suite. + * @param name The name to set + */ + public void setName(String name) { + fName= name; + } + + /** + * Returns the name of the suite. Not all + * test suites have a name and this method + * can return null. + */ + public String getName() { + return fName; + } + + /** + * Returns a test which will fail and log a warning message. + */ + private static Test warning(final String message) { + return new TestCase("warning") { + protected void runTest() { + fail(message); + } + }; + } +} |