001: /*
002: * Copyright 2006-2007, Unitils.org
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.unitils.core;
017:
018: import java.lang.reflect.Method;
019: import java.util.List;
020: import java.util.Properties;
021:
022: /**
023: * Core class of the Unitils library, and the main entry point that gives access to the {@link TestContext} and the
024: * different {@link Module}s.
025: * <p/>
026: * An instance of Unitils is configured with a certain configuration using the {@link #init(Properties)} method. Normally,
027: * only one instance of Unitils exists at any time. The default instance can be obtained using the {@link #getInstance()} method.
028: * This default instance can be set to a custom initialized instance or instance of a custom subclass using
029: * {@link #setInstance(Unitils)}.
030: * <p/>
031: * If not set, the singleton instance is initialized by default using {@link #initSingletonInstance()}. This method uses
032: * the {@link ConfigurationLoader} to load the configuration. An instance of {@link ModulesRepository} is used to
033: * initialize and maintain the modules.
034: * <p/>
035: * Unitils itself is also implemented as a module. In fact, an instance of Unitils behaves like a module who's behaviour
036: * is defined by the added behaviour of all modules.
037: */
038: public class Unitils implements Module {
039:
040: /* The singleton instance */
041: private static Unitils unitils;
042:
043: /**
044: * Returns the singleton instance
045: *
046: * @return the singleton instance, not null
047: */
048: public static synchronized Unitils getInstance() {
049: if (unitils == null) {
050: initSingletonInstance();
051: }
052: return unitils;
053: }
054:
055: /**
056: * Sets the singleton instance to the given object
057: *
058: * @param unitils the singleton instance
059: */
060: public static void setInstance(Unitils unitils) {
061: Unitils.unitils = unitils;
062: }
063:
064: /**
065: * Initializes the singleton instance to the default value, loading the configuration using the {@link
066: * ConfigurationLoader}
067: */
068: public static void initSingletonInstance() {
069: unitils = new Unitils();
070: unitils.init();
071: }
072:
073: /* Repository for all modules that are currently active in Unitils */
074: private ModulesRepository modulesRepository;
075:
076: /* Configuration of Unitils, made up of different properties files */
077: private Properties configuration;
078:
079: /* Object keeping track of the unit test that is currently running */
080: private TestContext testContext;
081:
082: /**
083: * Creates a new instance.
084: */
085: public Unitils() {
086: testContext = new TestContext();
087: }
088:
089: /**
090: * Initializes unitils with the configuration files.
091: */
092: public void init() {
093: init((String) null);
094: }
095:
096: /**
097: * Initializes unitils with the given custom configuration file
098: *
099: * @param customConfigurationFileName The name of the custom configuration file
100: */
101: public void init(String customConfigurationFileName) {
102: ConfigurationLoader configurationLoader = new ConfigurationLoader();
103: Properties properties = configurationLoader
104: .loadConfiguration(customConfigurationFileName);
105: init(properties);
106: }
107:
108: /**
109: * Initializes Unitils with the given configuration. All the modules that are configured in the given configuration
110: * are also created and initialized with this configuration.
111: *
112: * @param configuration The config, not null
113: */
114: public void init(Properties configuration) {
115: this .configuration = configuration;
116: modulesRepository = createModulesRepository(configuration);
117: }
118:
119: /**
120: * Creates a new instance of {@link TestListener}. This instance provides hook callback methods that enable intervening
121: * during the execution of unit tests.
122: *
123: * @return A new instance of {@link TestListener}
124: */
125: public TestListener createTestListener() {
126: return new UnitilsTestListener();
127: }
128:
129: /**
130: * Returns the {@link ModulesRepository} that provides access to the modules that are configured in unitils.
131: *
132: * @return the {@link ModulesRepository}
133: */
134: public ModulesRepository getModulesRepository() {
135: return modulesRepository;
136: }
137:
138: /**
139: * Returns the {@link TestContext} that, during the execution of the test suite, keeps track of the current test
140: * object, class and test method that are executing.
141: *
142: * @return the {@link TestContext}
143: */
144: public TestContext getTestContext() {
145: return testContext;
146: }
147:
148: /**
149: * Returns all properties that are used to configure unitils and the different modules.
150: *
151: * @return a <code>Properties</code> object
152: */
153: public Properties getConfiguration() {
154: return configuration;
155: }
156:
157: /**
158: * Configures all unitils modules using the given <code>Properties</code> object, and stores them in a {@link
159: * ModulesRepository}. The configuration of the modules is delegated to a {@link ModulesLoader} instance.
160: *
161: * @param configuration The config, not null
162: * @return a new {@link ModulesRepository}
163: */
164: protected ModulesRepository createModulesRepository(
165: Properties configuration) {
166: ModulesLoader modulesLoader = new ModulesLoader();
167: List<Module> modules = modulesLoader.loadModules(configuration);
168: return new ModulesRepository(modules);
169: }
170:
171: /**
172: * Implementation of {@link TestListener} that ensures that at every point during the run of a test, every {@link
173: * Module} gets the chance of performing some behavior, by calling the {@link TestListener} of each module in turn.
174: * Also makes sure that the state of the instance of {@link TestContext} returned by {@link Unitils#getTestContext()}
175: * is correctly set to the current test class, test object and test method.
176: */
177: private class UnitilsTestListener extends TestListener {
178:
179: @Override
180: public void beforeAll() {
181: TestContext testContext = getTestContext();
182: testContext.setTestClass(null);
183: testContext.setTestObject(null);
184: testContext.setTestMethod(null);
185:
186: List<Module> modules = modulesRepository.getModules();
187: for (Module module : modules) {
188: modulesRepository.getTestListener(module).beforeAll();
189: }
190: }
191:
192: @Override
193: public void beforeTestClass(Class<?> testClass) {
194: TestContext testContext = getTestContext();
195: testContext.setTestClass(testClass);
196: testContext.setTestObject(null);
197: testContext.setTestMethod(null);
198:
199: List<Module> modules = modulesRepository.getModules();
200: for (Module module : modules) {
201: modulesRepository.getTestListener(module)
202: .beforeTestClass(testClass);
203: }
204: }
205:
206: @Override
207: public void beforeTestSetUp(Object testObject) {
208: TestContext testContext = getTestContext();
209: testContext.setTestClass(testObject.getClass());
210: testContext.setTestObject(testObject);
211: testContext.setTestMethod(null);
212:
213: List<Module> modules = modulesRepository.getModules();
214: for (Module module : modules) {
215: modulesRepository.getTestListener(module)
216: .beforeTestSetUp(testObject);
217: }
218: }
219:
220: @Override
221: public void beforeTestMethod(Object testObject,
222: Method testMethod) {
223: TestContext testContext = getTestContext();
224: testContext.setTestClass(testObject.getClass());
225: testContext.setTestObject(testObject);
226: testContext.setTestMethod(testMethod);
227:
228: List<Module> modules = modulesRepository.getModules();
229: for (Module module : modules) {
230: modulesRepository.getTestListener(module)
231: .beforeTestMethod(testObject, testMethod);
232: }
233: }
234:
235: @Override
236: public void afterTestMethod(Object testObject,
237: Method testMethod, Throwable throwable) {
238: TestContext testContext = getTestContext();
239: testContext.setTestClass(testObject.getClass());
240: testContext.setTestObject(testObject);
241: testContext.setTestMethod(testMethod);
242:
243: List<Module> modules = modulesRepository.getModules();
244: for (Module module : modules) {
245: modulesRepository.getTestListener(module)
246: .afterTestMethod(testObject, testMethod,
247: throwable);
248: }
249: }
250:
251: @Override
252: public void afterTestTearDown(Object testObject) {
253: TestContext testContext = getTestContext();
254: testContext.setTestClass(testObject.getClass());
255: testContext.setTestObject(testObject);
256: testContext.setTestMethod(null);
257:
258: List<Module> modules = modulesRepository.getModules();
259: for (Module module : modules) {
260: modulesRepository.getTestListener(module)
261: .afterTestTearDown(testObject);
262: }
263: }
264:
265: @Override
266: public void afterTestClass(Class<?> testClass) {
267: TestContext testContext = getTestContext();
268: testContext.setTestClass(testClass);
269: testContext.setTestObject(null);
270: testContext.setTestMethod(null);
271:
272: List<Module> modules = modulesRepository.getModules();
273: for (Module module : modules) {
274: modulesRepository.getTestListener(module)
275: .afterTestClass(testClass);
276: }
277: }
278:
279: @Override
280: public void afterAll() {
281: TestContext testContext = getTestContext();
282: testContext.setTestClass(null);
283: testContext.setTestObject(null);
284: testContext.setTestMethod(null);
285:
286: List<Module> modules = modulesRepository.getModules();
287: for (Module module : modules) {
288: modulesRepository.getTestListener(module).afterAll();
289: }
290: }
291: }
292:
293: }
|