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 org.apache.maven.surefire.report.ReporterManager;
23  import org.apache.maven.surefire.testset.AbstractTestSet;
24  import org.apache.maven.surefire.testset.TestSetFailedException;
25  
26  import java.lang.reflect.Constructor;
27  import java.lang.reflect.InvocationTargetException;
28  import java.lang.reflect.Method;
29  import java.lang.reflect.Modifier;
30  import java.lang.reflect.Proxy;
31  
32  public final class JUnitTestSet
33      extends AbstractTestSet
34  {
35      public static final String TEST_CASE = "junit.framework.Test";
36  
37      public static final String TEST_RESULT = "junit.framework.TestResult";
38  
39      public static final String TEST_LISTENER = "junit.framework.TestListener";
40  
41      public static final String TEST = "junit.framework.Test";
42  
43      public static final String ADD_LISTENER_METHOD = "addListener";
44  
45      public static final String RUN_METHOD = "run";
46  
47      public static final String COUNT_TEST_CASES_METHOD = "countTestCases";
48  
49      public static final String SETUP_METHOD = "setUp";
50  
51      public static final String TEARDOWN_METHOD = "tearDown";
52  
53      private static final String TEST_SUITE = "junit.framework.TestSuite";
54  
55      private Class[] interfacesImplementedByDynamicProxy;
56  
57      private Class testResultClass;
58  
59      private Method addListenerMethod;
60  
61      private Method countTestCasesMethod;
62  
63      private Method runMethod;
64  
65      private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
66  
67      private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
68  
69      public JUnitTestSet( Class testClass )
70          throws TestSetFailedException
71      {
72          super( testClass );
73  
74          processTestClass();
75      }
76  
77      private void processTestClass()
78          throws TestSetFailedException
79      {
80          try
81          {
82              Class testClass = getTestClass();
83              ClassLoader loader = testClass.getClassLoader();
84  
85              testResultClass = loader.loadClass( TEST_RESULT );
86  
87              Class testListenerInterface = loader.loadClass( TEST_LISTENER );
88  
89              Class testInterface = loader.loadClass( TEST );
90  
91              // ----------------------------------------------------------------------
92              // Strategy for executing JUnit tests
93              //
94              // o look for the suite method and if that is present execute that method
95              //   to get the test object.
96              //
97              // o look for test classes that are assignable from TestCase
98              //
99              // o look for test classes that only implement the Test interface
100             // ----------------------------------------------------------------------
101 
102             interfacesImplementedByDynamicProxy = new Class[1];
103 
104             interfacesImplementedByDynamicProxy[0] = testListenerInterface;
105 
106             // The interface implemented by the dynamic proxy (TestListener), happens to be
107             // the same as the param types of TestResult.addTestListener
108             Class[] addListenerParamTypes = interfacesImplementedByDynamicProxy;
109 
110             addListenerMethod = testResultClass.getMethod( ADD_LISTENER_METHOD, addListenerParamTypes );
111 
112             if ( testInterface.isAssignableFrom( testClass ) )//testObject.getClass() ) )
113             {
114                 countTestCasesMethod = testInterface.getMethod( COUNT_TEST_CASES_METHOD, EMPTY_CLASS_ARRAY );
115 
116                 runMethod = testInterface.getMethod( RUN_METHOD, new Class[]{testResultClass} );
117 
118             }
119             else
120             {
121                 countTestCasesMethod = testClass.getMethod( COUNT_TEST_CASES_METHOD, EMPTY_CLASS_ARRAY );
122 
123                 runMethod = testClass.getMethod( RUN_METHOD, new Class[]{testResultClass} );
124             }
125         }
126         catch ( ClassNotFoundException e )
127         {
128             throw new TestSetFailedException( "JUnit classes not available", e );
129         }
130         catch ( NoSuchMethodException e )
131         {
132             throw new TestSetFailedException( "Class is not a JUnit TestCase", e );
133         }
134     }
135 
136     private static Object constructTestObject( Class testClass )
137         throws IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException,
138         ClassNotFoundException
139     {
140         Object testObject = createInstanceFromSuiteMethod( testClass );
141 
142         if ( testObject == null && testClass.getClassLoader().loadClass( TEST_CASE ).isAssignableFrom( testClass ) )
143         {
144             Class[] constructorParamTypes = {Class.class};
145 
146             Constructor constructor =
147                 testClass.getClassLoader().loadClass( TEST_SUITE ).getConstructor( constructorParamTypes );
148 
149             Object[] constructorParams = {testClass};
150 
151             testObject = constructor.newInstance( constructorParams );
152         }
153 
154         if ( testObject == null )
155         {
156             Constructor testConstructor = getTestConstructor( testClass );
157 
158             if ( testConstructor.getParameterTypes().length == 0 )
159             {
160                 testObject = testConstructor.newInstance( EMPTY_OBJECT_ARRAY );
161             }
162             else
163             {
164                 testObject = testConstructor.newInstance( new Object[]{testClass.getName()} );
165             }
166         }
167         return testObject;
168     }
169 
170     private static Object createInstanceFromSuiteMethod( Class testClass )
171         throws IllegalAccessException, InvocationTargetException
172     {
173         Object testObject = null;
174         try
175         {
176             Method suiteMethod = testClass.getMethod( "suite", EMPTY_CLASS_ARRAY );
177 
178             if ( Modifier.isPublic( suiteMethod.getModifiers() ) && Modifier.isStatic( suiteMethod.getModifiers() ) )
179             {
180                 testObject = suiteMethod.invoke( null, EMPTY_CLASS_ARRAY );
181             }
182         }
183         catch ( NoSuchMethodException e )
184         {
185             // No suite method
186         }
187         return testObject;
188     }
189 
190     public void execute( ReporterManager reportManager, ClassLoader loader )
191         throws TestSetFailedException
192     {
193         Class testClass = getTestClass();
194 
195         try
196         {
197             Object testObject = constructTestObject( testClass );
198 
199             Object instanceOfTestResult = testResultClass.newInstance();
200 
201             TestListenerInvocationHandler invocationHandler =
202                 new TestListenerInvocationHandler( reportManager, instanceOfTestResult, loader );
203 
204             Object testListener =
205                 Proxy.newProxyInstance( loader, interfacesImplementedByDynamicProxy, invocationHandler );
206 
207             Object[] addTestListenerParams = {testListener};
208 
209             addListenerMethod.invoke( instanceOfTestResult, addTestListenerParams );
210 
211             Object[] runParams = {instanceOfTestResult};
212 
213             runMethod.invoke( testObject, runParams );
214         }
215         catch ( IllegalArgumentException e )
216         {
217             throw new TestSetFailedException( testClass.getName(), e );
218         }
219         catch ( InstantiationException e )
220         {
221             throw new TestSetFailedException( testClass.getName(), e );
222         }
223         catch ( IllegalAccessException e )
224         {
225             throw new TestSetFailedException( testClass.getName(), e );
226         }
227         catch ( InvocationTargetException e )
228         {
229             throw new TestSetFailedException( testClass.getName(), e.getTargetException() );
230         }
231         catch ( ClassNotFoundException e )
232         {
233             throw new TestSetFailedException( "JUnit classes not available", e );
234         }
235         catch ( NoSuchMethodException e )
236         {
237             throw new TestSetFailedException( "Class is not a JUnit TestCase", e );
238         }
239     }
240 
241     private static Constructor getTestConstructor( Class testClass )
242         throws NoSuchMethodException
243     {
244         Constructor constructor;
245         try
246         {
247             constructor = testClass.getConstructor( new Class[]{String.class} );
248         }
249         catch ( NoSuchMethodException e )
250         {
251             constructor = testClass.getConstructor( EMPTY_CLASS_ARRAY );
252         }
253         return constructor;
254     }
255 }