View Javadoc
1   package org.argeo.util;
2   
3   import java.lang.reflect.Method;
4   import java.util.ArrayList;
5   import java.util.Collections;
6   import java.util.List;
7   import java.util.Map;
8   import java.util.TreeMap;
9   
10  /** A generic tester based on Java assertions and functional programming. */
11  public class Tester {
12  	private Map<String, TesterStatus> results = Collections.synchronizedSortedMap(new TreeMap<>());
13  
14  	private ClassLoader classLoader;
15  
16  	/** Use {@link Thread#getContextClassLoader()} by default. */
17  	public Tester() {
18  		this(Thread.currentThread().getContextClassLoader());
19  	}
20  
21  	public Tester(ClassLoader classLoader) {
22  		this.classLoader = classLoader;
23  	}
24  
25  	public void execute(String className) {
26  		Class<?> clss;
27  		try {
28  			clss = classLoader.loadClass(className);
29  			boolean assertionsEnabled = clss.desiredAssertionStatus();
30  			if (!assertionsEnabled)
31  				throw new IllegalStateException("Test runner " + getClass().getName()
32  						+ " requires Java assertions to be enabled. Call the JVM with the -ea argument.");
33  		} catch (Exception e1) {
34  			throw new IllegalArgumentException("Cannot initalise test for " + className, e1);
35  
36  		}
37  		List<Method> methods = findMethods(clss);
38  		if (methods.size() == 0)
39  			throw new IllegalArgumentException("No test method found in " + clss);
40  		// TODO make order more predictable?
41  		for (Method method : methods) {
42  			String uid = method.getDeclaringClass().getName() + "#" + method.getName();
43  			TesterStatus testStatus = new TesterStatus(uid);
44  			Object obj = null;
45  			try {
46  				beforeTest(uid, method);
47  				obj = clss.getDeclaredConstructor().newInstance();
48  				method.invoke(obj);
49  				testStatus.setPassed();
50  				afterTestPassed(uid, method, obj);
51  			} catch (Exception e) {
52  				testStatus.setFailed(e);
53  				afterTestFailed(uid, method, obj, e);
54  			} finally {
55  				results.put(uid, testStatus);
56  			}
57  		}
58  	}
59  
60  	protected void beforeTest(String uid, Method method) {
61  		// System.out.println(uid + ": STARTING");
62  	}
63  
64  	protected void afterTestPassed(String uid, Method method, Object obj) {
65  		System.out.println(uid + ": PASSED");
66  	}
67  
68  	protected void afterTestFailed(String uid, Method method, Object obj, Throwable e) {
69  		System.out.println(uid + ": FAILED");
70  		e.printStackTrace();
71  	}
72  
73  	protected List<Method> findMethods(Class<?> clss) {
74  		List<Method> methods = new ArrayList<Method>();
75  //		Method call = getMethod(clss, "call");
76  //		if (call != null)
77  //			methods.add(call);
78  //
79  		for (Method method : clss.getMethods()) {
80  			if (method.getName().startsWith("test")) {
81  				methods.add(method);
82  			}
83  		}
84  		return methods;
85  	}
86  
87  	protected Method getMethod(Class<?> clss, String name, Class<?>... parameterTypes) {
88  		try {
89  			return clss.getMethod(name, parameterTypes);
90  		} catch (NoSuchMethodException e) {
91  			return null;
92  		} catch (SecurityException e) {
93  			throw new IllegalStateException(e);
94  		}
95  	}
96  
97  	public static void main(String[] args) {
98  		// deal with arguments
99  		String className;
100 		if (args.length < 1) {
101 			System.err.println(usage());
102 			System.exit(1);
103 			throw new IllegalArgumentException();
104 		} else {
105 			className = args[0];
106 		}
107 
108 		Tester test = new Tester();
109 		try {
110 			test.execute(className);
111 		} catch (Throwable e) {
112 			e.printStackTrace();
113 		}
114 
115 		Map<String, TesterStatus> r = test.results;
116 		for (String uid : r.keySet()) {
117 			TesterStatus testStatus = r.get(uid);
118 			System.out.println(testStatus);
119 		}
120 	}
121 
122 	public static String usage() {
123 		return "java " + Tester.class.getName() + " [test class name]";
124 
125 	}
126 }