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 }