KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > internal > client > ClientTestCaseCaller


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

20 package org.apache.cactus.internal.client;
21
22 import java.lang.reflect.InvocationTargetException JavaDoc;
23 import java.lang.reflect.Method JavaDoc;
24
25 import junit.framework.Assert;
26 import junit.framework.Test;
27
28 import org.apache.cactus.Request;
29 import org.apache.cactus.internal.util.JUnitVersionHelper;
30 import org.apache.cactus.internal.util.TestCaseImplementChecker;
31 import org.apache.cactus.spi.client.ResponseObjectFactory;
32 import org.apache.cactus.spi.client.connector.ProtocolHandler;
33 import org.apache.cactus.spi.client.connector.ProtocolState;
34 import org.apache.commons.logging.Log;
35 import org.apache.commons.logging.LogFactory;
36
37 /**
38  * Provides the ability to run common code before and after each test on the
39  * client side. All the methods provided are independent of any communication
40  * protocol between client side and server side (HTTP, JMS, etc). Any protocol
41  * dependent methods must be provided and implemented in the
42  * {@link ProtocolHandler} implementation class.
43  *
44  * @version $Id: ClientTestCaseCaller.java,v 1.1 2004/05/22 11:34:47 vmassol Exp $
45  */

46 public class ClientTestCaseCaller extends Assert
47 {
48     /**
49      * The prefix of a test method.
50      */

51     protected static final String JavaDoc TEST_METHOD_PREFIX = "test";
52
53     /**
54      * The prefix of a begin test method.
55      */

56     protected static final String JavaDoc BEGIN_METHOD_PREFIX = "begin";
57
58     /**
59      * The prefix of an end test method.
60      */

61     protected static final String JavaDoc END_METHOD_PREFIX = "end";
62
63     /**
64      * The name of the method that is called before each test on the client
65      * side (if it exists).
66      */

67     protected static final String JavaDoc CLIENT_GLOBAL_BEGIN_METHOD = "begin";
68
69     /**
70      * The name of the method that is called after each test on the client
71      * side (if it exists).
72      */

73     protected static final String JavaDoc CLIENT_GLOBAL_END_METHOD = "end";
74
75     /**
76      * The logger (only used on the client side).
77      */

78     private Log logger;
79
80     /**
81      * Pure JUnit Test Case that we are wrapping (if any)
82      */

83     private Test wrappedTest;
84
85     /**
86      * The test we are delegating for.
87      */

88     private Test delegatedTest;
89
90     /**
91      * The protocol handler to use to execute the tests on the server side.
92      */

93     private ProtocolHandler protocolHandler;
94
95     // Constructors ---------------------------------------------------------
96

97     /**
98      * @param theDelegatedTest the test we are delegating for
99      * @param theWrappedTest the test being wrapped by this delegate (or null
100      * if none)
101      * @param theProtocolHandler the protocol handler to use to execute the
102      * tests on the server side
103      */

104     public ClientTestCaseCaller(Test theDelegatedTest,
105         Test theWrappedTest, ProtocolHandler theProtocolHandler)
106     {
107         if (theDelegatedTest == null)
108         {
109             throw new IllegalStateException JavaDoc(
110                 "The test object passed must not be null");
111         }
112
113         setDelegatedTest(theDelegatedTest);
114         setWrappedTest(theWrappedTest);
115         this.protocolHandler = theProtocolHandler;
116     }
117
118     // Public methods -------------------------------------------------------
119

120     /**
121      * Execute begin and end methods and calls the different
122      * {@link ProtocolHandler} lifecycle methods to execute the test
123      * on the server side.
124      *
125      * Note that this method is overriden from the JUnit
126      * {@link junit.framework.TestCase} class in order to prevent JUnit from
127      * calling the {@link junit.framework.TestCase#setUp()} and
128      * {@link junit.framework.TestCase#tearDown()} methods on the client side.
129      * instead we are calling the server redirector proxy and the setup and
130      * teardown methods will be executed on the server side.
131      *
132      * @exception Throwable if any error happens during the execution of
133      * the test
134      */

135     public void runTest() throws Throwable JavaDoc
136     {
137         Request request = this.protocolHandler.createRequest();
138         
139         // Call the set up and begin methods to fill the request object
140
callGlobalBeginMethod(request);
141         callBeginMethod(request);
142
143         // Run the server test
144
ProtocolState state = this.protocolHandler.runTest(
145             getDelegatedTest(), getWrappedTest(), request);
146         
147         // Call the end method
148
Object JavaDoc response = callEndMethod(request,
149             this.protocolHandler.createResponseObjectFactory(state));
150
151         // call the tear down method
152
callGlobalEndMethod(request,
153             this.protocolHandler.createResponseObjectFactory(state),
154             response);
155
156         this.protocolHandler.afterTest(state);
157     }
158
159     /**
160      * @return The logger used by the <code>TestCase</code> class and
161      * subclasses to perform logging.
162      */

163     public final Log getLogger()
164     {
165         return this.logger;
166     }
167
168     /**
169      * Perform client side initializations before each test, such as
170      * re-initializating the logger and printing some logging information.
171      */

172     public void runBareInit()
173     {
174         // We make sure we reinitialize The logger with the name of the
175
// current extending class so that log statements will contain the
176
// actual class name (that's why the logged instance is not static).
177
this.logger = LogFactory.getLog(this.getClass());
178
179         // Mark beginning of test on client side
180
getLogger().debug("------------- Test: " + this.getCurrentTestName());
181     }
182
183     /**
184      * Call the test case begin method.
185      *
186      * @param theRequest the request object to pass to the begin method.
187      * @exception Throwable any error that occurred when calling the begin
188      * method for the current test case.
189      */

190     public void callBeginMethod(Request theRequest) throws Throwable JavaDoc
191     {
192         callGenericBeginMethod(theRequest, getBeginMethodName());
193     }
194
195     /**
196      * Call the test case end method
197      *
198      * @param theRequest the request data that were used to open the
199      * connection.
200      * @param theResponseFactory the factory to use to return response objects.
201      * @return the created Reponse object
202      * @exception Throwable any error that occurred when calling the end method
203      * for the current test case.
204      */

205     public Object JavaDoc callEndMethod(Request theRequest,
206         ResponseObjectFactory theResponseFactory) throws Throwable JavaDoc
207     {
208         return callGenericEndMethod(theRequest, theResponseFactory,
209             getEndMethodName(), null);
210     }
211
212     /**
213      * Call the global begin method. This is the method that is called before
214      * each test if it exists. It is called on the client side only.
215      *
216      * @param theRequest the request object which will contain data that will
217      * be used to connect to the Cactus server side redirectors.
218      * @exception Throwable any error that occurred when calling the method
219      */

220     public void callGlobalBeginMethod(Request theRequest) throws Throwable JavaDoc
221     {
222         callGenericBeginMethod(theRequest, CLIENT_GLOBAL_BEGIN_METHOD);
223     }
224
225     /**
226      * Call the client tear down up method if it exists.
227      *
228      * @param theRequest the request data that were used to open the
229      * connection.
230      * @param theResponseFactory the factory to use to return response objects.
231      * @param theResponse the Response object if it exists. Can be null in
232      * which case it is created from the response object factory
233      * @exception Throwable any error that occurred when calling the method
234      */

235     private void callGlobalEndMethod(Request theRequest,
236         ResponseObjectFactory theResponseFactory, Object JavaDoc theResponse)
237         throws Throwable JavaDoc
238     {
239         callGenericEndMethod(theRequest, theResponseFactory,
240             CLIENT_GLOBAL_END_METHOD, theResponse);
241     }
242     
243     // Private methods ------------------------------------------------------
244

245     /**
246      * @param theWrappedTest the pure JUnit test that we need to wrap
247      */

248     private void setWrappedTest(Test theWrappedTest)
249     {
250         this.wrappedTest = theWrappedTest;
251     }
252
253     /**
254      * @param theDelegatedTest the test we are delegating for
255      */

256     private void setDelegatedTest(Test theDelegatedTest)
257     {
258         this.delegatedTest = theDelegatedTest;
259     }
260
261     /**
262      * @return the wrapped JUnit test
263      */

264     private Test getWrappedTest()
265     {
266         return this.wrappedTest;
267     }
268
269     /**
270      * @return the test we are delegating for
271      */

272     private Test getDelegatedTest()
273     {
274         return this.delegatedTest;
275     }
276
277     /**
278      * @return the test on which we will operate. If there is a wrapped
279      * test then the returned test is the wrapped test. Otherwise we
280      * return the delegated test.
281      */

282     private Test getTest()
283     {
284         Test activeTest;
285         if (getWrappedTest() != null)
286         {
287             activeTest = getWrappedTest();
288         }
289         else
290         {
291             activeTest = getDelegatedTest();
292         }
293         return activeTest;
294     }
295
296     /**
297      * @return the name of the test method to call without the
298      * TEST_METHOD_PREFIX prefix
299      */

300     private String JavaDoc getBaseMethodName()
301     {
302         // Sanity check
303
if (!getCurrentTestName().startsWith(TEST_METHOD_PREFIX))
304         {
305             throw new RuntimeException JavaDoc("bad name ["
306                 + getCurrentTestName()
307                 + "]. It should start with ["
308                 + TEST_METHOD_PREFIX + "].");
309         }
310
311         return getCurrentTestName().substring(
312             TEST_METHOD_PREFIX.length());
313     }
314
315     /**
316      * @return the name of the test begin method to call that initialize the
317      * test by initializing the <code>WebRequest</code> object
318      * for the test case.
319      */

320     private String JavaDoc getBeginMethodName()
321     {
322         return BEGIN_METHOD_PREFIX + getBaseMethodName();
323     }
324
325     /**
326      * @return the name of the test end method to call when the test has been
327      * run on the server. It can be used to verify returned headers,
328      * cookies, ...
329      */

330     private String JavaDoc getEndMethodName()
331     {
332         return END_METHOD_PREFIX + getBaseMethodName();
333     }
334
335     /**
336      * Call a begin method which takes Cactus WebRequest as parameter
337      *
338      * @param theRequest the request object which will contain data that will
339      * be used to connect to the Cactus server side redirectors.
340      * @param theMethodName the name of the begin method to call
341      * @exception Throwable any error that occurred when calling the method
342      */

343     private void callGenericBeginMethod(Request theRequest,
344         String JavaDoc theMethodName) throws Throwable JavaDoc
345     {
346         // First, verify if a begin method exist. If one is found, verify if
347
// it has the correct signature. If not, send a warning.
348
Method JavaDoc[] methods = getTest().getClass().getMethods();
349
350         for (int i = 0; i < methods.length; i++)
351         {
352             if (methods[i].getName().equals(theMethodName))
353             {
354                 TestCaseImplementChecker.checkAsBeginMethod(methods[i]);
355
356                 try
357                 {
358                     methods[i].invoke(getTest(), new Object JavaDoc[] {theRequest});
359
360                     break;
361                 }
362                 catch (InvocationTargetException JavaDoc e)
363                 {
364                     e.fillInStackTrace();
365                     throw e.getTargetException();
366                 }
367                 catch (IllegalAccessException JavaDoc e)
368                 {
369                     e.fillInStackTrace();
370                     throw e;
371                 }
372             }
373         }
374     }
375
376     /**
377      * Call the global end method. This is the method that is called after
378      * each test if it exists. It is called on the client side only.
379      *
380      * @param theRequest the request data that were used to open the
381      * connection.
382      * @param theResponseFactory the factory to use to return response objects.
383      * @param theMethodName the name of the end method to call
384      * @param theResponse the Response object if it exists. Can be null in
385      * which case it is created from the response object factory
386      * @return the created Reponse object
387      * @exception Throwable any error that occurred when calling the end method
388      * for the current test case.
389      */

390     private Object JavaDoc callGenericEndMethod(Request theRequest,
391         ResponseObjectFactory theResponseFactory, String JavaDoc theMethodName,
392         Object JavaDoc theResponse) throws Throwable JavaDoc
393     {
394         Method JavaDoc methodToCall = null;
395         Object JavaDoc paramObject = null;
396
397         Method JavaDoc[] methods = getTest().getClass().getMethods();
398
399         for (int i = 0; i < methods.length; i++)
400         {
401             if (methods[i].getName().equals(theMethodName))
402             {
403                 TestCaseImplementChecker.checkAsEndMethod(methods[i]);
404
405                 paramObject = theResponse;
406
407                 if (paramObject == null)
408                 {
409                     Class JavaDoc[] parameters = methods[i].getParameterTypes();
410                     try
411                     {
412                         paramObject = theResponseFactory.getResponseObject(
413                             parameters[0].getName(), theRequest);
414                     }
415                     catch (ClientException e)
416                     {
417                         throw new ClientException("The method ["
418                             + methods[i].getName()
419                             + "] has a bad parameter of type ["
420                             + parameters[0].getName() + "]", e);
421                     }
422                 }
423
424                 // Has a method to call already been found ?
425
if (methodToCall != null)
426                 {
427                     fail("There can only be one method ["
428                        + methods[i].getName() + "] per test case. "
429                        + "Test case [" + this.getCurrentTestName()
430                        + "] has two at least !");
431                 }
432
433                 methodToCall = methods[i];
434             }
435         }
436
437         if (methodToCall != null)
438         {
439             try
440             {
441                 methodToCall.invoke(getTest(), new Object JavaDoc[] {paramObject});
442             }
443             catch (InvocationTargetException JavaDoc e)
444             {
445                 e.fillInStackTrace();
446                 throw e.getTargetException();
447             }
448             catch (IllegalAccessException JavaDoc e)
449             {
450                 e.fillInStackTrace();
451                 throw e;
452             }
453         }
454
455         return paramObject;
456     }
457     
458     /**
459      * @return the name of the current test case being executed (it corresponds
460      * to the name of the test method with the "test" prefix removed.
461      * For example, for "testSomeTestOk" would return "someTestOk".
462      */

463     private String JavaDoc getCurrentTestName()
464     {
465         return JUnitVersionHelper.getTestCaseName(getDelegatedTest());
466     }
467 }
468
Popular Tags