Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/meterware/servletunit/JUnitServlet.java


1   package com.meterware.servletunit;
2   /********************************************************************************************************************
3    * $Id: JUnitServlet.java,v 1.7 2003/07/22 01:49:08 russgold Exp $
4    *
5    * Copyright (c) 2001-2003, Russell Gold
6    *
7    * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8    * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9    * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
10   * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11   *
12   * The above copyright notice and this permission notice shall be included in all copies or substantial portions
13   * of the Software.
14   *
15   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16   * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
18   * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19   * DEALINGS IN THE SOFTWARE.
20   *
21   *******************************************************************************************************************/
22  import java.io.IOException;
23  import java.io.PrintWriter;
24  import java.util.Enumeration;
25  
26  import javax.servlet.http.HttpServlet;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  import javax.servlet.ServletException;
30  
31  import junit.runner.BaseTestRunner;
32  import junit.runner.TestSuiteLoader;
33  import junit.runner.StandardTestSuiteLoader;
34  import junit.framework.Test;
35  import junit.framework.AssertionFailedError;
36  import junit.framework.TestResult;
37  import junit.framework.TestFailure;
38  
39  
40  /**
41   * A servlet which can run unit tests inside a servlet context.  It may be extended to provide InvocationContext-access
42   * to such tests if a container-specific implementation of InvocationContextFactory is provided.
43   * Combined with ServletTestCase, this would permit
44   * in-container tests of servlets in a fashion similar to that supported by ServletUnit.
45   *
46   * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
47   **/
48  public class JUnitServlet extends HttpServlet {
49  
50      public JUnitServlet() {
51      }
52  
53  
54      protected JUnitServlet( InvocationContextFactory factory ) {
55          _factory = factory;
56      }
57  
58  
59      protected void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
60          ResultsFormatter formatter = getResultsFormatter( request.getParameter( "format" ) );
61          response.setContentType( formatter.getContentType() );
62          final String testName = request.getParameter( "test" );
63          if (testName == null || testName.length() == 0) {
64              reportCannotRunTest( response.getWriter(), "No test class specified" );
65          } else {
66              ServletTestRunner runner = new ServletTestRunner( response.getWriter(), formatter );
67              runner.runTestSuite( testName );
68          }
69          response.getWriter().close();
70      }
71  
72  
73      private ResultsFormatter getResultsFormatter( String formatterName ) {
74          if ("text".equalsIgnoreCase( formatterName )) {
75              return new TextResultsFormatter();
76          } else if ("xml".equalsIgnoreCase( formatterName )) {
77              return new XMLResultsFormatter();
78          } else {
79              return new HTMLResultsFormatter();
80          }
81      }
82  
83  
84      private InvocationContextFactory _factory;
85  
86  
87      private void reportCannotRunTest( PrintWriter writer, final String errorMessage ) {
88          writer.print( "<html><head><title>Cannot run test</title></head><body>" + errorMessage + "</body></html>" );
89      }
90  
91  
92      class ServletTestRunner extends BaseTestRunner {
93          private PrintWriter _writer;
94          private ResultsFormatter _formatter;
95  
96  
97          public ServletTestRunner( PrintWriter writer, ResultsFormatter formatter ) {
98              ServletTestCase.setInvocationContextFactory( _factory );
99              _writer = writer;
100             _formatter = formatter;
101         }
102 
103 
104         void runTestSuite( String testClassName ) {
105             Test suite = getTest( testClassName );
106 
107             if (suite != null) {
108                 TestResult testResult = new TestResult();
109                 testResult.addListener( this );
110                 long startTime= System.currentTimeMillis();
111                 suite.run( testResult );
112                 long endTime= System.currentTimeMillis();
113                 _formatter.displayResults( _writer, testClassName, elapsedTimeAsString( endTime-startTime ), testResult );
114             }
115         }
116 
117 
118         public void addError( Test test, Throwable throwable ) {
119         }
120 
121 
122         public void addFailure( Test test, AssertionFailedError error ) {
123         }
124 
125 
126         public void endTest( Test test ) {
127         }
128 
129 
130         protected void runFailed( String s ) {
131             reportCannotRunTest( _writer, s );
132         }
133 
134 
135         public void startTest( Test test ) {
136         }
137 
138 
139         public void testStarted( String s ) {
140         }
141 
142 
143         public void testEnded( String s ) {
144         }
145 
146 
147         public void testFailed( int i, Test test, Throwable throwable ) {
148         }
149 
150 
151         /**
152          * Always use the StandardTestSuiteLoader. Overridden from
153          * BaseTestRunner.
154          */
155         public TestSuiteLoader getLoader() {
156             return new StandardTestSuiteLoader();
157         }
158 
159     }
160 
161 
162     static abstract class ResultsFormatter {
163 
164         private static final char LF = 10;
165         private static final char CR = 13;
166 
167 
168         abstract String getContentType();
169 
170 
171         void displayResults( PrintWriter writer, String testClassName, String elapsedTimeString, TestResult testResult ) {
172             displayHeader( writer, testClassName, testResult, elapsedTimeString );
173             displayResults( writer, testResult );
174             displayFooter( writer );
175         }
176 
177 
178         protected abstract void displayHeader( PrintWriter writer, String testClassName, TestResult testResult, String elapsedTimeString );
179 
180 
181         protected abstract void displayResults( PrintWriter writer, TestResult testResult );
182 
183 
184         protected abstract void displayFooter( PrintWriter writer );
185 
186 
187         protected String sgmlEscape( String s ) {
188             if (s == null) return "NULL";
189             StringBuffer result = new StringBuffer( s.length() );
190             char[] chars = s.toCharArray();
191             for (int i = 0; i < chars.length; i++) {
192                 switch( chars[i] ) {
193                 case '&':
194                     result.append( "&amp;" );
195                     break;
196                 case '<':
197                     result.append( "&lt;" );
198                     break;
199                 case '>':
200                     result.append( "&gt;" );
201                     break;
202                 case LF:
203                     if (i > 0 && chars[i-1] == CR) {
204                         result.append( chars[i] );
205                         break;
206                     }
207                 case CR:
208                     result.append( getLineBreak() );
209                 default:
210                     result.append( chars[i] );
211                 }
212             }
213             return result.toString();
214         }
215 
216 
217         protected String getLineBreak() {
218             return "<br>";
219         }
220     }
221 
222 
223     abstract static class DisplayedResultsFormatter extends ResultsFormatter {
224 
225         protected void displayHeader( PrintWriter writer, String testClassName, TestResult testResult, String elapsedTimeString ) {
226             displayHeader( writer, testClassName, getFormatted( testResult.runCount(), "test" ),
227                                    elapsedTimeString, testResult.wasSuccessful() ? "OK" : "Problems Occurred" );
228         }
229 
230         protected void displayResults( PrintWriter writer, TestResult testResult ) {
231             if (!testResult.wasSuccessful()) {
232                 displayProblems( writer, "failure", testResult.failureCount(), testResult.failures() );
233                 displayProblems( writer, "error", testResult.errorCount(), testResult.errors() );
234             }
235         }
236 
237 
238         protected abstract void displayHeader( PrintWriter writer, String testClassName, String testCountText, String elapsedTimeString, String resultString );
239 
240 
241         protected abstract void displayProblemTitle( PrintWriter writer, String title );
242 
243 
244         protected abstract void displayProblemDetailHeader( PrintWriter writer, int i, String testName );
245 
246 
247         protected abstract void displayProblemDetailFooter( PrintWriter writer );
248 
249 
250         protected abstract void displayProblemDetail( PrintWriter writer, String message );
251 
252 
253         private void displayProblems( PrintWriter writer, String kind, int count, Enumeration enumeration ) {
254             if (count != 0) {
255                 displayProblemTitle( writer, getFormatted( count, kind ) );
256                 Enumeration e = enumeration;
257                 for (int i = 1; e.hasMoreElements(); i++) {
258                     TestFailure failure = (TestFailure) e.nextElement();
259                     displayProblemDetailHeader( writer, i, failure.failedTest().toString() );
260                     if (failure.thrownException() instanceof AssertionFailedError) {
261                         displayProblemDetail( writer, failure.thrownException().getMessage() );
262                     } else {
263                         displayProblemDetail( writer, BaseTestRunner.getFilteredTrace( failure.thrownException() ) );
264                     }
265                     displayProblemDetailFooter( writer );
266                 }
267             }
268         }
269 
270 
271         private String getFormatted( int count, String name ) {
272             return count + " " + name + (count == 1 ? "" : "s");
273         }
274 
275 
276     }
277 
278 
279     static class TextResultsFormatter extends DisplayedResultsFormatter {
280 
281         String getContentType() {
282             return "text/plain";
283         }
284 
285 
286         protected void displayHeader( PrintWriter writer, String testClassName, String testCountText,
287                                       String elapsedTimeString, String resultString ) {
288             writer.println( testClassName + " (" + testCountText + "): " + resultString );
289         }
290 
291 
292         protected void displayFooter( PrintWriter writer ) {
293         }
294 
295 
296         protected void displayProblemTitle( PrintWriter writer, String title ) {
297             writer.println();
298             writer.println( title + ':' );
299         }
300 
301 
302         protected void displayProblemDetailHeader( PrintWriter writer, int i, String testName ) {
303             writer.println( i + ". " + testName + ":" );
304         }
305 
306 
307         protected void displayProblemDetailFooter( PrintWriter writer ) {
308             writer.println();
309         }
310 
311 
312         protected void displayProblemDetail( PrintWriter writer, String message ) {
313             writer.println( message );
314         }
315     }
316 
317 
318     static class HTMLResultsFormatter extends DisplayedResultsFormatter {
319 
320         String getContentType() {
321             return "text/html";
322         }
323 
324 
325         protected void displayHeader( PrintWriter writer, String testClassName, String testCountText,
326                                       String elapsedTimeString, String resultString ) {
327             writer.println( "<html><head><title>Test Suite: " + testClassName + "</title>" );
328             writer.println( "<style type='text/css'>" );
329             writer.println( "<!--" );
330             writer.println( "  td.detail { font-size:smaller; vertical-align: top }" );
331             writer.println( "  -->" );
332             writer.println( "</style></head><body>" );
333             writer.println( "<table id='results' border='1'><tr>" );
334             writer.println( "<td>" + testCountText + "</td>" );
335             writer.println( "<td>Time: " + elapsedTimeString + "</td>" );
336             writer.println( "<td>" + resultString + "</td></tr>" );
337         }
338 
339 
340         protected void displayFooter( PrintWriter writer ) {
341             writer.println( "</table>" );
342             writer.println( "</body></html>" );
343         }
344 
345 
346         protected void displayProblemTitle( PrintWriter writer, String title ) {
347             writer.println( "<tr><td colspan=3>" + title + "</td></tr>" );
348         }
349 
350 
351         protected void displayProblemDetailHeader( PrintWriter writer, int i, String testName ) {
352             writer.println( "<tr><td class='detail' align='right'>" + i + "</td>" );
353             writer.println( "<td class='detail'>" + testName + "</td><td class='detail'>" );
354         }
355 
356 
357         protected void displayProblemDetailFooter( PrintWriter writer ) {
358             writer.println( "</td></tr>" );
359         }
360 
361 
362         protected void displayProblemDetail( PrintWriter writer, String message ) {
363             writer.println( sgmlEscape( message ) );
364         }
365 
366     }
367 
368 
369 
370     static class XMLResultsFormatter extends ResultsFormatter {
371 
372         String getContentType() {
373             return "text/xml;charset=UTF-8";
374         }
375 
376 
377         protected void displayHeader( PrintWriter writer, String testClassName, TestResult testResult, String elapsedTimeString ) {
378             writer.println( "<?xml version='1.0' encoding='UTF-8' ?>\n" +
379                             "<testsuite name=" + asAttribute( testClassName ) +
380                                       " tests=" + asAttribute( testResult.runCount() ) +
381                                       " failures=" + asAttribute( testResult.failureCount() ) +
382                                       " errors=" + asAttribute( testResult.errorCount() ) +
383                                       " time=" + asAttribute( elapsedTimeString ) + ">" );
384         }
385 
386 
387         private String asAttribute( int value ) {
388             return '"' + Integer.toString( value ) + '"';
389         }
390 
391 
392         private String asAttribute( String value ) {
393             return '"' + sgmlEscape( value ) + '"';
394         }
395 
396 
397         protected void displayFooter( PrintWriter writer ) {
398             writer.println( "</testsuite>" );
399         }
400 
401 
402         protected void displayResults( PrintWriter writer, TestResult testResult ) {
403             displayResults( writer, "failure", testResult.failures() );
404             displayResults( writer, "error", testResult.errors() );
405         }
406 
407 
408         private void displayResults( PrintWriter writer, String failureNodeName, Enumeration resultsEnumeration ) {
409             for (Enumeration e = resultsEnumeration; e.hasMoreElements();) {
410                 TestFailure failure = (TestFailure) e.nextElement();
411                 writer.println( "  <testcase name=" + asAttribute( failure.failedTest().toString() ) + ">" );
412                 writer.print( "    <" + failureNodeName + " type=" + asAttribute( failure.thrownException().getClass().getName() ) +
413                                                       " message=" + asAttribute( failure.exceptionMessage() ) );
414                 if (!displayException( failure )) {
415                     writer.println( "/>" );
416                 } else {
417                     writer.println( ">" );
418                     writer.print( sgmlEscape( BaseTestRunner.getFilteredTrace( failure.thrownException() ) ) );
419                     writer.println( "    </" + failureNodeName + ">" );
420                 }
421                 writer.println( "  </testcase>" );
422             }
423         }
424 
425 
426         private boolean displayException( TestFailure failure ) {
427             return true;
428         }
429 
430 
431         protected String getLineBreak() {
432             return "";
433         }
434     }
435 
436 
437 }