View Javadoc

1   package org.apache.maven.surefire.junit;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.InvocationTargetException;
23  import java.lang.reflect.Method;
24  import java.lang.reflect.Modifier;
25  import java.util.ArrayList;
26  import java.util.List;
27  import org.apache.maven.surefire.report.LegacyPojoStackTraceWriter;
28  import org.apache.maven.surefire.report.ReportEntry;
29  import org.apache.maven.surefire.report.RunListener;
30  import org.apache.maven.surefire.report.SimpleReportEntry;
31  import org.apache.maven.surefire.testset.TestSetFailedException;
32  
33  public class PojoTestSet
34      implements SurefireTestSet
35  {
36  
37      private static final String TEST_METHOD_PREFIX = "test";
38  
39      private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
40  
41      private final Object testObject;
42  
43      private List<Method> testMethods;
44  
45      private Method setUpMethod;
46  
47      private Method tearDownMethod;
48  
49      private final Class testClass;
50  
51      public PojoTestSet( Class testClass )
52          throws TestSetFailedException
53      {
54          if ( testClass == null )
55          {
56              throw new NullPointerException( "testClass is null" );
57          }
58  
59          this.testClass = testClass;
60  
61          try
62          {
63              testObject = testClass.newInstance();
64          }
65          catch ( InstantiationException e )
66          {
67              throw new TestSetFailedException( "Unable to instantiate POJO '" + testClass + "'", e );
68          }
69          catch ( IllegalAccessException e )
70          {
71              throw new TestSetFailedException( "Unable to instantiate POJO '" + testClass + "'", e );
72          }
73      }
74  
75      public void execute( RunListener reportManager, ClassLoader loader )
76          throws TestSetFailedException
77      {
78          if ( reportManager == null )
79          {
80              throw new NullPointerException( "reportManager is null" );
81          }
82  
83          executeTestMethods( reportManager );
84      }
85  
86      private void executeTestMethods( RunListener reportManager )
87      {
88          if ( reportManager == null )
89          {
90              throw new NullPointerException( "reportManager is null" );
91          }
92  
93          if ( testMethods == null )
94          {
95              discoverTestMethods();
96          }
97  
98          boolean abort = false;
99  
100         for ( int i = 0; i < testMethods.size() && !abort; ++i )
101         {
102             abort = executeTestMethod( testMethods.get( i ), EMPTY_OBJECT_ARRAY, reportManager );
103         }
104     }
105 
106     private boolean executeTestMethod( Method method, Object[] args, RunListener reportManager )
107     {
108         if ( method == null || args == null || reportManager == null )
109         {
110             throw new NullPointerException();
111         }
112 
113         String userFriendlyMethodName = method.getName() + '(';
114 
115         if ( args.length != 0 )
116         {
117             userFriendlyMethodName += "Reporter";
118         }
119 
120         userFriendlyMethodName += ')';
121 
122         ReportEntry report =
123             new SimpleReportEntry( testObject.getClass().getName(), getTestName( userFriendlyMethodName ) );
124 
125         reportManager.testStarting( report );
126 
127         try
128         {
129             setUpFixture();
130         }
131         catch ( Throwable e )
132         {
133             report =
134                 SimpleReportEntry.withException( testObject.getClass().getName(), getTestName( userFriendlyMethodName ),
135                                                  new LegacyPojoStackTraceWriter( testObject.getClass().getName(),
136                                                                                  method.getName(), e ) );
137 
138             reportManager.testFailed( report );
139 
140             // A return value of true indicates to this class's executeTestMethods
141             // method that it should abort and not attempt to execute
142             // any other test methods. The other caller of this method,
143             // TestRerunner.rerun, ignores this return value, because it is
144             // only running one test.
145             return true;
146         }
147 
148         // Make sure that tearDownFixture
149         try
150         {
151             method.invoke( testObject, args );
152 
153             report = new SimpleReportEntry( testObject.getClass().getName(), getTestName( userFriendlyMethodName ) );
154 
155             reportManager.testSucceeded( report );
156         }
157         catch ( InvocationTargetException ite )
158         {
159             Throwable t = ite.getTargetException();
160 
161             report =
162                 SimpleReportEntry.withException( testObject.getClass().getName(), getTestName( userFriendlyMethodName ),
163                                                  new LegacyPojoStackTraceWriter( testObject.getClass().getName(),
164                                                                                  method.getName(), t ) );
165 
166             reportManager.testFailed( report );
167             // Don't return  here, because tearDownFixture should be called even
168             // if the test method throws an exception.
169         }
170         catch ( Throwable t )
171         {
172             report =
173                 SimpleReportEntry.withException( testObject.getClass().getName(), getTestName( userFriendlyMethodName ),
174                                                  new LegacyPojoStackTraceWriter( testObject.getClass().getName(),
175                                                                                  method.getName(), t ) );
176 
177             reportManager.testFailed( report );
178             // Don't return  here, because tearDownFixture should be called even
179             // if the test method throws an exception.
180         }
181 
182         try
183         {
184             tearDownFixture();
185         }
186         catch ( Throwable t )
187         {
188             // Treat any exception from tearDownFixture as a failure of the test.
189             report =
190                 SimpleReportEntry.withException( testObject.getClass().getName(), getTestName( userFriendlyMethodName ),
191                                                  new LegacyPojoStackTraceWriter( testObject.getClass().getName(),
192                                                                                  method.getName(), t ) );
193 
194             reportManager.testFailed( report );
195 
196             // A return value of true indicates to this class's executeTestMethods
197             // method that it should abort and not attempt to execute
198             // any other test methods. The other caller of this method,
199             // TestRerunner.rerun, ignores this return value, because it is
200             // only running one test.
201             return true;
202         }
203 
204         // A return value of false indicates to this class's executeTestMethods
205         // method that it should keep plowing ahead and invoke more test methods.
206         // The other caller of this method,
207         // TestRerunner.rerun, ignores this return value, because it is
208         // only running one test.
209         return false;
210     }
211 
212     private String getTestName( String testMethodName )
213     {
214         if ( testMethodName == null )
215         {
216             throw new NullPointerException( "testMethodName is null" );
217         }
218 
219         return getTestClass().getName() + "." + testMethodName;
220     }
221 
222     private void setUpFixture()
223         throws Throwable
224     {
225         if ( setUpMethod != null )
226         {
227             setUpMethod.invoke( testObject );
228         }
229     }
230 
231     private void tearDownFixture()
232         throws Throwable
233     {
234         if ( tearDownMethod != null )
235         {
236             tearDownMethod.invoke( testObject );
237         }
238     }
239 
240     private void discoverTestMethods()
241     {
242         if ( testMethods == null )
243         {
244             testMethods = new ArrayList<Method>();
245 
246             Method[] methods = getTestClass().getMethods();
247 
248             for ( Method m : methods )
249             {
250                 if ( isValidTestMethod( m ) )
251                 {
252                     String simpleName = m.getName();
253 
254                     // name must have 5 or more chars
255                     if ( simpleName.length() > 4 )
256                     {
257                         String firstFour = simpleName.substring( 0, 4 );
258 
259                         // name must start with "test"
260                         if ( firstFour.equals( TEST_METHOD_PREFIX ) )
261                         {
262                             testMethods.add( m );
263                         }
264                     }
265                 }
266                 else if ( m.getName().equals( "setUp" ) && m.getParameterTypes().length == 0 )
267                 {
268                     setUpMethod = m;
269                 }
270                 else if ( m.getName().equals( "tearDown" ) && m.getParameterTypes().length == 0 )
271                 {
272                     tearDownMethod = m;
273                 }
274             }
275         }
276     }
277 
278     private static boolean isValidTestMethod( Method m )
279     {
280         boolean isInstanceMethod = !Modifier.isStatic( m.getModifiers() );
281 
282         boolean returnsVoid = m.getReturnType().equals( void.class );
283 
284         boolean hasNoParams = m.getParameterTypes().length == 0;
285 
286         return isInstanceMethod && returnsVoid && hasNoParams;
287     }
288 
289     public String getName()
290     {
291         return testClass.getName();
292     }
293 
294     public Class getTestClass()
295     {
296         return testClass;
297     }
298 }