View Javadoc
1   package auxtestlib;
2   
3   import java.util.HashMap;
4   import java.util.Map;
5   import java.util.Properties;
6   
7   import org.junit.Assert;
8   
9   /**
10   * <p>
11   * Super class for all test helpers.
12   * </p>
13   * <p>
14   * In general, subclasses should override {@link #mySetUp()} and
15   * {@link #myTearDown()} to create and destroy (using the {@link #tearDown()}
16   * method) helpers they depend on. All test preparation should be done in the
17   * {@link #myPrepareFixture()} and all clean up done in {@link #myCleanUp()}.
18   * </p>
19   * <p>
20   * Clean up should be an idempotent operation (meaning it should be able to run
21   * several times and have the same effect as running a single one). This is
22   * important because test case execution may be aborted and disposal of
23   * resources may not be done. {@link #myPrepareFixture()} is always called after
24   * clean up so it can assume the test fixture has been previously cleaned.
25   * </p>
26   * <p>
27   * As a general example, temporary tables should be dropped in the clean up
28   * method and created in the prepare fixture. However, the clean up method
29   * should be prepared to cope with the error arising from the table not
30   * existing. The prepare fixture method, on the other hand, should not catch
31   * errors because it is guaranteed that the table has been previously removed.
32   * </p>
33   * <p>
34   * Note that <em>all</em> helper variables should be static as the
35   * {@link #mySetUp()} method is called when the first helper (of a specific
36   * class) is created and the {@link #myTearDown()} is called when the last
37   * helper (of a specific class) is destroyed.
38   * </p>
39   */
40  public abstract class AbstractTestHelper extends Assert {
41  	/**
42  	 * Total number of helpers created.
43  	 */
44  	private static int helperCount;
45  
46  	/**
47  	 * System properties that existed before the test started.
48  	 */
49  	private static Properties systemProperties;
50  
51  	/**
52  	 * Number of helpers of each type created.
53  	 */
54  	private static Map<Class<?>, Integer> helperCounter;
55  
56  	/**
57  	 * Creates a new test helper.
58  	 * 
59  	 * @throws Exception failed
60  	 */
61  	public AbstractTestHelper() throws Exception {
62  		/**
63  		 * Check if we're initializing the first helper. If so, call globalInit.
64  		 */
65  		helperCount++;
66  		if (helperCount == 1) {
67  			globalInit();
68  		}
69  
70  		/**
71  		 * Check if we're initializing the first helper of this type. If so,
72  		 * call helperInit.
73  		 */
74  		Class<?> myClass = getClass();
75  		Integer cnt = helperCounter.get(myClass);
76  		if (cnt == null) {
77  			helperCounter.put(myClass, 0);
78  			helperInit();
79  		}
80  
81  		helperCounter.put(myClass, helperCounter.get(myClass) + 1);
82  	}
83  
84  	/**
85  	 * Destroys a test helper.
86  	 * 
87  	 * @throws Exception failed
88  	 */
89  	public final void tearDown() throws Exception {
90  		/**
91  		 * Check if we're destroying the last helper, call helperTearDown.
92  		 */
93  		Class<?> myClass = getClass();
94  		int hcnt = helperCounter.get(myClass) - 1;
95  		helperCounter.put(myClass, hcnt);
96  		if (hcnt == 0) {
97  			helperCounter.remove(myClass);
98  			helperTearDown();
99  		}
100 
101 		/**
102 		 * Check if we're destroying the last helper. If so, globalTearDown.
103 		 */
104 		helperCount--;
105 		if (helperCount == 0) {
106 			globalTearDown();
107 		}
108 	}
109 
110 	/**
111 	 * Initializes the helpers (called when the first helper is initialized).
112 	 * 
113 	 * @throws Exception failed
114 	 */
115 	private static void globalInit() throws Exception {
116 		helperCounter = new HashMap<>();
117 		TestPropertiesDefinition.load_global_properties();
118 		systemProperties = new Properties();
119 		systemProperties.putAll(System.getProperties());
120 	}
121 
122 	/**
123 	 * Destroys the helpers (called when the last helper is destroyed).
124 	 */
125 	private static void globalTearDown() {
126 		helperCounter = null;
127 		Properties p = new Properties();
128 		p.putAll(systemProperties);
129 		System.setProperties(p);
130 	}
131 
132 	/**
133 	 * Initializes a helper.
134 	 * 
135 	 * @throws Exception failed
136 	 */
137 	private void helperInit() throws Exception {
138 		mySetUp();
139 		myCleanUp();
140 		myPrepareFixture();
141 	}
142 
143 	/**
144 	 * Destroys a helper.
145 	 * 
146 	 * @throws Exception failed
147 	 */
148 	private void helperTearDown() throws Exception {
149 		myCleanUp();
150 		myTearDown();
151 	}
152 
153 	/**
154 	 * Gets a test property which has to be defined. The property is obtained as
155 	 * a string.
156 	 * 
157 	 * @param key the property key (the package name will be automatically
158 	 * prepended)
159 	 * 
160 	 * @return the property value
161 	 */
162 	public final String getPropMString(String key) {
163 		return TestPropertiesDefinition.getMString(prependPackage(key));
164 	}
165 
166 	/**
167 	 * Gets a test property which has to be defined. The property is obtained as
168 	 * an integer.
169 	 * 
170 	 * @param key the property key (the package name will be automatically
171 	 * prepended)
172 	 * 
173 	 * @return the property value
174 	 */
175 	public final int getPropInt(String key) {
176 		return TestPropertiesDefinition.getInt(prependPackage(key));
177 	}
178 
179 	/**
180 	 * Gets a test property which has to be defined. The property is obtained as
181 	 * a double.
182 	 * 
183 	 * @param key the property key (the package name will be automatically
184 	 * prepended)
185 	 * 
186 	 * @return the property value
187 	 */
188 	public final double getPropDouble(String key) {
189 		return TestPropertiesDefinition.getDouble(prependPackage(key));
190 	}
191 
192 	/**
193 	 * Prepends the package name to a key.
194 	 * 
195 	 * @param key the key
196 	 * 
197 	 * @return the key with the package name prepended
198 	 */
199 	private String prependPackage(String key) {
200 		String pkg;
201 
202 		pkg = this.getClass().getCanonicalName();
203 		int idx = pkg.lastIndexOf('.');
204 		return pkg.substring(0, idx + 1) + key;
205 	}
206 
207 	/**
208 	 * Obtains the total number of helpers created. This may be useful to check
209 	 * if we leak helpers.
210 	 * 
211 	 * @return the total number of helpers created
212 	 */
213 	public static int getTotalHelperCount() {
214 		return helperCount;
215 	}
216 
217 	/**
218 	 * Prepares the helper for execution. This method is invoked when the first
219 	 * helper of this class is created.
220 	 * 
221 	 * @throws Exception failed
222 	 */
223 	protected abstract void mySetUp() throws Exception;
224 
225 	/**
226 	 * Destroys the helper. This method is invoked when the last helper of this
227 	 * class is destroyed.
228 	 * 
229 	 * @throws Exception failed
230 	 */
231 	protected abstract void myTearDown() throws Exception;
232 
233 	/**
234 	 * Cleans all data that may have been generated by this run or previous run
235 	 * of the helper.
236 	 * 
237 	 * @throws Exception failed
238 	 */
239 	protected abstract void myCleanUp() throws Exception;
240 
241 	/**
242 	 * Prepares data for the test.
243 	 * 
244 	 * @throws Exception failed
245 	 */
246 	protected abstract void myPrepareFixture() throws Exception;
247 }