View Javadoc

1   /**
2    * Pyx4me framework
3    * Copyright (C) 2005-2007 Michael Lifshits
4    * Copyright (C) 2005-2007 Vlad Skarzhevskyy
5    *
6    * @version $Id: ReflectionTestCaseHelper.java 2815 2008-12-11 21:23:40Z vlads $
7    */
8   package cldcunit.runner;
9   
10  import java.lang.reflect.Constructor;
11  import java.lang.reflect.InvocationTargetException;
12  import java.lang.reflect.Method;
13  import java.lang.reflect.Modifier;
14  import java.util.Vector;
15  
16  import junit.framework.Test;
17  import junit.framework.TestCase;
18  import junit.framework.TestMethod;
19  
20  public class ReflectionTestCaseHelper extends BaseTestCaseHelper {
21  
22  	public static final String SUITE_METHODNAME = "suite";
23  
24  	public ReflectionTestCaseHelper() {
25  	}
26  
27  	public TestMethod[] createAllTestMethods() {
28  		Vector testMethodsVector = new Vector();
29  		try {
30  			getTestConstructor(getTestCase().getClass()); // Avoid generating multiple error messages
31  		} catch (NoSuchMethodException e) {
32  			testMethodsVector.addElement(createWarningTestMethod("Class " + getTestCase().getName()
33  					+ " has no public constructor TestCase(String name) or TestCase()"));
34  			return (TestMethod[]) testMethodsVector.toArray(new TestMethod[0]);
35  		}
36  
37  		if (!Modifier.isPublic(getTestCase().getClass().getModifiers())) {
38  			testMethodsVector
39  					.addElement(createWarningTestMethod("Class " + getTestCase().getName() + " is not public"));
40  			return (TestMethod[]) testMethodsVector.toArray(new TestMethod[0]);
41  		}
42  
43  		Class superClass = getTestCase().getClass();
44  		while (Test.class.isAssignableFrom(superClass)) {
45  			Method[] methods = superClass.getDeclaredMethods();
46  			for (int i = 0; i < methods.length; i++) {
47  				if (isTestMethod(methods[i])) {
48  					if (!isPublicTestMethod(methods[i])) {
49  						testMethodsVector.addElement(createWarningTestMethod("Test method isn't public: "
50  								+ methods[i].getName()));
51  						return (TestMethod[]) testMethodsVector.toArray(new TestMethod[0]);
52  					} else {
53  						testMethodsVector.addElement(createTestMethod(methods[i].getName()));
54  					}
55  				}
56  			}
57  			superClass = superClass.getSuperclass();
58  		}
59  		if (testMethodsVector.size() == 0) {
60  			testMethodsVector.addElement(createWarningTestMethod("No tests found in "
61  					+ getTestCase().getClass().getName()));
62  			return (TestMethod[]) testMethodsVector.toArray(new TestMethod[0]);
63  		}
64  		return (TestMethod[]) testMethodsVector.toArray(new TestMethod[0]);
65  	}
66  
67  	/**
68  	 * Gets a constructor which takes a single String as its argument or a no arg constructor.
69  	 */
70  	public static Constructor getTestConstructor(Class theClass) throws NoSuchMethodException {
71  		Class[] args = { String.class };
72  		try {
73  			return theClass.getConstructor(args);
74  		} catch (NoSuchMethodException e) {
75  			// fall through
76  		}
77  		return theClass.getConstructor(new Class[0]);
78  	}
79  
80  	private boolean isPublicTestMethod(Method m) {
81  		return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
82  	}
83  
84  	private boolean isTestMethod(Method m) {
85  		String name = m.getName();
86  		Class[] parameters = m.getParameterTypes();
87  		Class returnType = m.getReturnType();
88  		return parameters.length == 0 && name.startsWith("test") && returnType.equals(Void.TYPE);
89  	}
90  
91  	private void runTest(junit.framework.TestCase testCase, String methodName) throws Throwable {
92  		Method runMethod = null;
93  		try {
94  			// use getMethod to get all public inherited
95  			// methods. getDeclaredMethods returns all
96  			// methods of this class but excludes the
97  			// inherited ones.
98  			runMethod = getTestCase().getClass().getMethod(methodName, null);
99  		} catch (NoSuchMethodException e) {
100 			TestCase.fail("Method \"" + methodName + "\" not found");
101 		}
102 		if (!Modifier.isPublic(runMethod.getModifiers())) {
103 			TestCase.fail("Method \"" + methodName + "\" should be public");
104 		}
105 
106 		try {
107 			runMethod.invoke(testCase, new Class[0]);
108 		} catch (InvocationTargetException e) {
109 			e.fillInStackTrace();
110 			throw e.getTargetException();
111 		} catch (IllegalAccessException e) {
112 			e.fillInStackTrace();
113 			throw e;
114 		}
115 	}
116 
117 	public TestMethod createTestMethod(String name) {
118 		return new TestMethod(name) {
119 			public void run(junit.framework.TestCase testCase) throws Throwable {
120 				runTest(testCase, this.getName());
121 			}
122 		};
123 	}
124 
125 	public TestMethod createWarningTestMethod(final String message) {
126 		return new TestMethod("warning") {
127 			public void run(junit.framework.TestCase testCase) throws Throwable {
128 				TestCase.fail(message);
129 			}
130 		};
131 	}
132 
133 	public Test getSuite() {
134 		Method suiteMethod = null;
135 		try {
136 			suiteMethod = getTestCase().getClass().getMethod(SUITE_METHODNAME, new Class[0]);
137 		} catch (Exception e) {
138 			return null;
139 		}
140 		if (!Modifier.isStatic(suiteMethod.getModifiers())) {
141 			TestCase.fail("Suite() method must be static");
142 			return null;
143 		}
144 		Test test = null;
145 		try {
146 			test = (Test) suiteMethod.invoke(null, new Class[0]); // static method
147 			if (test == null)
148 				return test;
149 		} catch (InvocationTargetException e) {
150 			TestCase.fail("Failed to invoke suite():" + e.getTargetException().toString());
151 			return null;
152 		} catch (IllegalAccessException e) {
153 			TestCase.fail("Failed to invoke suite():" + e.toString());
154 			return null;
155 		}
156 
157 		return test;
158 	}
159 }