1 package junit.framework; 2 3 import java.util.Vector; 4 import java.util.Enumeration; 5 import java.io.PrintWriter;import java.io.StringWriter;import java.lang.reflect.*; 6 import java.lang.reflect.Constructor; 7 8 /** 9 * A <code>TestSuite</code> is a <code>Composite</code> of Tests. 10 * It runs a collection of test cases. Here is an example using 11 * the dynamic test definition. 12 * <pre> 13 * TestSuite suite= new TestSuite(); 14 * suite.addTest(new MathTest("testAdd")); 15 * suite.addTest(new MathTest("testDivideByZero")); 16 * </pre> 17 * Alternatively, a TestSuite can extract the tests to be run automatically. 18 * To do so you pass the class of your TestCase class to the 19 * TestSuite constructor. 20 * <pre> 21 * TestSuite suite= new TestSuite(MathTest.class); 22 * </pre> 23 * This constructor creates a suite with all the methods 24 * starting with "test" that take no arguments. 25 * 26 * @see Test 27 */ 28 public class TestSuite implements Test { 29 30 private Vector<Test> fTests= new Vector<Test>(10); 31 private String fName; 32 33 /** 34 * Constructs an empty TestSuite. 35 */ 36 public TestSuite() { 37 } 38 39 /** 40 * Constructs a TestSuite from the given class with the given name. 41 * @see TestSuite#TestSuite(Class) 42 */ 43 public TestSuite(Class theClass, String name) { 44 this(theClass); 45 setName(name); 46 } 47 48 /** 49 * Constructs a TestSuite from the given class. Adds all the methods 50 * starting with "test" as test cases to the suite. 51 * Parts of this method was written at 2337 meters in the Huffihutte, 52 * Kanton Uri 53 */ 54 public TestSuite(final Class theClass) { 55 fName= theClass.getName(); 56 try { 57 getTestConstructor(theClass); // Avoid generating multiple error messages 58 } catch (NoSuchMethodException e) { 59 addTest(warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()")); 60 return; 61 } 62 63 if (!Modifier.isPublic(theClass.getModifiers())) { 64 addTest(warning("Class "+theClass.getName()+" is not public")); 65 return; 66 } 67 68 Class superClass= theClass; 69 Vector<String> names= new Vector<String>(); 70 while (Test.class.isAssignableFrom(superClass)) { 71 Method[] methods= superClass.getDeclaredMethods(); 72 for (int i= 0; i < methods.length; i++) { 73 addTestMethod(methods[i], names, theClass); 74 } 75 superClass= superClass.getSuperclass(); 76 } 77 if (fTests.size() == 0) 78 addTest(warning("No tests found in "+theClass.getName())); 79 } 80 81 /** 82 * Constructs an empty TestSuite. 83 */ 84 public TestSuite(String name) { 85 setName(name); 86 } 87 88 /** 89 * Adds a test to the suite. 90 */ 91 public void addTest(Test test) { 92 fTests.addElement(test); 93 } 94 95 /** 96 * Adds the tests from the given class to the suite 97 */ 98 public void addTestSuite(Class testClass) { 99 addTest(new TestSuite(testClass)); 100 } 101 102 private void addTestMethod(Method m, Vector<String> names, Class theClass) { 103 String name= m.getName(); 104 if (names.contains(name)) 105 return; 106 if (! isPublicTestMethod(m)) { 107 if (isTestMethod(m)) 108 addTest(warning("Test method isn't public: "+m.getName())); 109 return; 110 } 111 names.addElement(name); 112 addTest(createTest(theClass, name)); 113 } 114 115 /** 116 * ...as the moon sets over the early morning Merlin, Oregon 117 * mountains, our intrepid adventurers type... 118 */ 119 static public Test createTest(Class theClass, String name) { 120 Constructor constructor; 121 try { 122 constructor= getTestConstructor(theClass); 123 } catch (NoSuchMethodException e) { 124 return warning("Class "+theClass.getName()+" has no public constructor TestCase(String name) or TestCase()"); 125 } 126 Object test; 127 try { 128 if (constructor.getParameterTypes().length == 0) { 129 test= constructor.newInstance(new Object[0]); 130 if (test instanceof TestCase) 131 ((TestCase) test).setName(name); 132 } else { 133 test= constructor.newInstance(new Object[]{name}); 134 } 135 } catch (InstantiationException e) { 136 return(warning("Cannot instantiate test case: "+name+" ("+exceptionToString(e)+")")); 137 } catch (InvocationTargetException e) { 138 return(warning("Exception in constructor: "+name+" ("+exceptionToString(e.getTargetException())+")")); 139 } catch (IllegalAccessException e) { 140 return(warning("Cannot access test case: "+name+" ("+exceptionToString(e)+")")); 141 } 142 return (Test) test; 143 } 144 145 /** 146 * Converts the stack trace into a string 147 */ 148 private static String exceptionToString(Throwable t) { 149 StringWriter stringWriter= new StringWriter(); 150 PrintWriter writer= new PrintWriter(stringWriter); 151 t.printStackTrace(writer); 152 return stringWriter.toString(); 153 154 } 155 156 /** 157 * Counts the number of test cases that will be run by this test. 158 */ 159 public int countTestCases() { 160 int count= 0; 161 for (Enumeration e= tests(); e.hasMoreElements(); ) { 162 Test test= (Test)e.nextElement(); 163 count= count + test.countTestCases(); 164 } 165 return count; 166 } 167 168 /** 169 * Gets a constructor which takes a single String as 170 * its argument or a no arg constructor. 171 */ 172 public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException { 173 Class[] args= { String.class }; 174 try { 175 return theClass.getConstructor(args); 176 } catch (NoSuchMethodException e) { 177 // fall through 178 } 179 return theClass.getConstructor(new Class[0]); 180 } 181 182 private boolean isPublicTestMethod(Method m) { 183 return isTestMethod(m) && Modifier.isPublic(m.getModifiers()); 184 } 185 186 private boolean isTestMethod(Method m) { 187 String name= m.getName(); 188 Class[] parameters= m.getParameterTypes(); 189 Class returnType= m.getReturnType(); 190 return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE); 191 } 192 193 /** 194 * Runs the tests and collects their result in a TestResult. 195 */ 196 public void run(TestResult result) { 197 for (Enumeration e= tests(); e.hasMoreElements(); ) { 198 if (result.shouldStop() ) 199 break; 200 Test test= (Test)e.nextElement(); 201 runTest(test, result); 202 } 203 } 204 205 public void runTest(Test test, TestResult result) { 206 test.run(result); 207 } 208 209 /** 210 * Returns the test at the given index 211 */ 212 public Test testAt(int index) { 213 return (Test)fTests.elementAt(index); 214 } 215 216 /** 217 * Returns the number of tests in this suite 218 */ 219 public int testCount() { 220 return fTests.size(); 221 } 222 223 /** 224 * Returns the tests as an enumeration 225 */ 226 public Enumeration tests() { 227 return fTests.elements(); 228 } 229 230 /** 231 */ 232 public String toString() { 233 if (getName() != null) 234 return getName(); 235 return super.toString(); 236 } 237 238 /** 239 * Sets the name of the suite. 240 * @param name The name to set 241 */ 242 public void setName(String name) { 243 fName= name; 244 } 245 246 /** 247 * Returns the name of the suite. Not all 248 * test suites have a name and this method 249 * can return null. 250 */ 251 public String getName() { 252 return fName; 253 } 254 255 /** 256 * Returns a test which will fail and log a warning message. 257 */ 258 private static Test warning(final String message) { 259 return new TestCase("warning") { 260 protected void runTest() { 261 fail(message); 262 } 263 }; 264 } 265 } 266