Home | History | Annotate | Download | only in framework
      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