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