KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > logging > PathableTestSuite


1 /*
2  * Copyright 2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.logging;
18
19 import java.util.Properties JavaDoc;
20
21 import junit.framework.Test;
22 import junit.framework.TestResult;
23 import junit.framework.TestSuite;
24
25 /**
26  * Custom TestSuite class that can be used to control the context classloader
27  * in operation when a test runs.
28  * <p>
29  * For tests that need to control exactly what the classloader hierarchy is
30  * like when the test is run, something like the following is recommended:
31  * <pre>
32  * class SomeTestCase extends TestCase {
33  * public static Test suite() throws Exception {
34  * PathableClassLoader parent = new PathableClassLoader(null);
35  * parent.useSystemLoader("junit.");
36  *
37  * PathableClassLoader child = new PathableClassLoader(parent);
38  * child.addLogicalLib("testclasses");
39  * child.addLogicalLib("log4j12");
40  * child.addLogicalLib("commons-logging");
41  *
42  * Class testClass = child.loadClass(SomeTestCase.class.getName());
43  * ClassLoader contextClassLoader = child;
44  *
45  * PathableTestSuite suite = new PathableTestSuite(testClass, child);
46  * return suite;
47  * }
48  *
49  * // test methods go here
50  * }
51  * </pre>
52  * Note that if the suite method throws an exception then this will be handled
53  * reasonable gracefully by junit; it will report that the suite method for
54  * a test case failed with exception yyy.
55  * <p>
56  * The use of PathableClassLoader is not required to use this class, but it
57  * is expected that using the two classes together is common practice.
58  * <p>
59  * This class will run each test methods within the specified TestCase using
60  * the specified context classloader and system classloader. If different
61  * tests within the same class require different context classloaders,
62  * then the context classloader passed to the constructor should be the
63  * "lowest" one available, and tests that need the context set to some parent
64  * of this "lowest" classloader can call
65  * <pre>
66  * // NB: pseudo-code only
67  * setContextClassLoader(getContextClassLoader().getParent());
68  * </pre>
69  * This class ensures that any context classloader changes applied by a test
70  * is undone after the test is run, so tests don't need to worry about
71  * restoring the context classloader on exit. This class also ensures that
72  * the system properties are restored to their original settings after each
73  * test, so tests that manipulate those don't need to worry about resetting them.
74  * <p>
75  * This class does not provide facilities for manipulating system properties;
76  * tests that need specific system properties can simply set them in the
77  * fixture or at the start of a test method.
78  * <p>
79  * <b>Important!</b> When the test case is run, "this.getClass()" refers of
80  * course to the Class object passed to the constructor of this class - which
81  * is different from the class whose suite() method was executed to determine
82  * the classpath. This means that the suite method cannot communicate with
83  * the test cases simply by setting static variables (for example to make the
84  * custom classloaders available to the test methods or setUp/tearDown fixtures).
85  * If this is really necessary then it is possible to use reflection to invoke
86  * static methods on the class object passed to the constructor of this class.
87  * <p>
88  * <h2>Limitations</h2>
89  * <p>
90  * This class cannot control the system classloader (ie what method
91  * ClassLoader.getSystemClassLoader returns) because Java provides no
92  * mechanism for setting the system classloader. In this case, the only
93  * option is to invoke the unit test in a separate JVM with the appropriate
94  * settings.
95  * <p>
96  * The effect of using this approach in a system that uses junit's
97  * "reloading classloader" behaviour is unknown. This junit feature is
98  * intended for junit GUI apps where a test may be run multiple times
99  * within the same JVM - and in particular, when the .class file may
100  * be modified between runs of the test. How junit achieves this is
101  * actually rather weird (the whole junit code is rather weird in fact)
102  * and it is not clear whether this approach will work as expected in
103  * such situations.
104  */

105 public class PathableTestSuite extends TestSuite {
106
107     /**
108      * The classloader that should be set as the context classloader
109      * before each test in the suite is run.
110      */

111     private ClassLoader JavaDoc contextLoader;
112
113     /**
114      * Constructor.
115      *
116      * @param testClass is the TestCase that is to be run, as loaded by
117      * the appropriate ClassLoader.
118      *
119      * @param contextClassLoader is the loader that should be returned by
120      * calls to Thread.currentThread.getContextClassLoader from test methods
121      * (or any method called by test methods).
122      */

123     public PathableTestSuite(Class JavaDoc testClass, ClassLoader JavaDoc contextClassLoader) {
124         super(testClass);
125         contextLoader = contextClassLoader;
126     }
127
128     /**
129      * This method is invoked once for each Test in the current TestSuite.
130      * Note that a Test may itself be a TestSuite object (ie a collection
131      * of tests).
132      * <p>
133      * The context classloader and system properties are saved before each
134      * test, and restored after the test completes to better isolate tests.
135      */

136     public void runTest(Test test, TestResult result) {
137         ClassLoader JavaDoc origContext = Thread.currentThread().getContextClassLoader();
138         Properties JavaDoc oldSysProps = (Properties JavaDoc) System.getProperties().clone();
139         try {
140             Thread.currentThread().setContextClassLoader(contextLoader);
141             test.run(result);
142         } finally {
143             System.setProperties(oldSysProps);
144             Thread.currentThread().setContextClassLoader(origContext);
145         }
146     }
147 }
148
Popular Tags