1 package org.apache.maven.surefire.testng;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.File;
23 import java.lang.annotation.Annotation;
24 import java.lang.reflect.Method;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Properties;
31 import java.util.SortedMap;
32 import java.util.TreeMap;
33
34 import org.apache.maven.surefire.NonAbstractClassFilter;
35 import org.apache.maven.surefire.report.ConsoleOutputCapture;
36 import org.apache.maven.surefire.report.ConsoleOutputReceiver;
37 import org.apache.maven.surefire.report.ReportEntry;
38 import org.apache.maven.surefire.report.ReporterException;
39 import org.apache.maven.surefire.report.ReporterFactory;
40 import org.apache.maven.surefire.report.RunListener;
41 import org.apache.maven.surefire.report.SimpleReportEntry;
42 import org.apache.maven.surefire.testset.TestSetFailedException;
43 import org.apache.maven.surefire.util.RunOrderCalculator;
44 import org.apache.maven.surefire.util.ScanResult;
45 import org.apache.maven.surefire.util.TestsToRun;
46
47
48
49
50
51
52
53 public class TestNGDirectoryTestSuite
54 implements TestNgTestSuite
55 {
56
57 private final Map options;
58
59 private final Map junitOptions;
60
61 private final String testSourceDirectory;
62
63 private final File reportsDirectory;
64
65 private SortedMap<String, TestNGTestSet> testSets;
66
67 private final ScanResult scanResult;
68
69 private final String testMethodPattern;
70
71 private final RunOrderCalculator runOrderCalculator;
72
73 private final Class junitTestClass;
74
75 private Class<? extends Annotation> junitRunWithAnnotation;
76
77 private Class<? extends Annotation> junitTestAnnotation;
78
79 public TestNGDirectoryTestSuite( String testSourceDirectory, Properties confOptions, File reportsDirectory,
80 String testMethodPattern, RunOrderCalculator runOrderCalculator,
81 ScanResult scanResult )
82 {
83
84 this.runOrderCalculator = runOrderCalculator;
85
86 this.options = confOptions;
87
88 this.testSourceDirectory = testSourceDirectory;
89 this.reportsDirectory = reportsDirectory;
90 this.scanResult = scanResult;
91 this.testMethodPattern = testMethodPattern;
92 this.junitTestClass = findJUnitTestClass();
93 this.junitRunWithAnnotation = findJUnitRunWithAnnotation();
94 this.junitTestAnnotation = findJUnitTestAnnotation();
95 this.junitOptions = createJUnitOptions();
96 }
97
98 public void execute( TestsToRun testsToRun, ReporterFactory reporterManagerFactory )
99 throws TestSetFailedException
100 {
101
102 if ( !testsToRun.allowEagerReading() )
103 {
104 executeLazy( testsToRun, reporterManagerFactory );
105 }
106 else if ( testsToRun.containsAtLeast( 2 ) )
107 {
108 executeMulti( testsToRun, reporterManagerFactory );
109 }
110 else if ( testsToRun.containsAtLeast( 1 ) )
111 {
112 Class testClass = testsToRun.iterator().next();
113 executeSingleClass( reporterManagerFactory, testClass );
114 }
115 }
116
117 private void executeSingleClass( ReporterFactory reporterManagerFactory, Class testClass )
118 throws TestSetFailedException
119 {
120 this.options.put( "suitename", testClass.getName() );
121
122 RunListener reporter = reporterManagerFactory.createReporter();
123 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
124
125 startTestSuite( reporter, this );
126
127 final Map optionsToUse = isJUnitTest( testClass ) ? junitOptions : options;
128
129 TestNGExecutor.run( new Class[]{ testClass }, testSourceDirectory, optionsToUse, reporter, this,
130 reportsDirectory, testMethodPattern );
131
132 finishTestSuite( reporter, this );
133 }
134
135 public void executeLazy( TestsToRun testsToRun, ReporterFactory reporterFactory )
136 throws TestSetFailedException
137 {
138
139 for ( Class c : testsToRun )
140 {
141 executeSingleClass( reporterFactory, c );
142 }
143 }
144
145 private Class findJUnitTestClass()
146 {
147 return lookupClass( "junit.framework.Test" );
148 }
149
150 private Class findJUnitRunWithAnnotation()
151 {
152 return lookupClass( "org.junit.runner.RunWith" );
153 }
154
155 private Class findJUnitTestAnnotation()
156 {
157 return lookupClass( "org.junit.Test" );
158 }
159
160 private Class lookupClass( String className )
161 {
162 Class junitClass;
163 try
164 {
165 junitClass = Class.forName( className );
166 }
167 catch ( ClassNotFoundException e )
168 {
169 junitClass = null;
170 }
171 return junitClass;
172 }
173
174 public void executeMulti( TestsToRun testsToRun, ReporterFactory reporterFactory )
175 throws TestSetFailedException
176 {
177 List<Class> testNgTestClasses = new ArrayList<Class>();
178 List<Class> junitTestClasses = new ArrayList<Class>();
179 for ( Class c : testsToRun )
180 {
181 if ( isJUnitTest( c ) )
182 {
183 junitTestClasses.add( c );
184 }
185 else
186 {
187 testNgTestClasses.add( c );
188 }
189 }
190
191 File testNgReportsDirectory = reportsDirectory, junitReportsDirectory = reportsDirectory;
192
193 if ( junitTestClasses.size() > 0 && testNgTestClasses.size() > 0 )
194 {
195 testNgReportsDirectory = new File( reportsDirectory, "testng-native-results" );
196 junitReportsDirectory = new File( reportsDirectory, "testng-junit-results" );
197 }
198
199 RunListener reporterManager = reporterFactory.createReporter();
200 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporterManager );
201 startTestSuite( reporterManager, this );
202
203 Class[] testClasses = testNgTestClasses.toArray( new Class[testNgTestClasses.size()] );
204
205 TestNGExecutor.run( testClasses, this.testSourceDirectory, options, reporterManager, this,
206 testNgReportsDirectory, testMethodPattern );
207
208 if ( junitTestClasses.size() > 0 )
209 {
210 testClasses = junitTestClasses.toArray( new Class[junitTestClasses.size()] );
211
212 TestNGExecutor.run( testClasses, testSourceDirectory, junitOptions, reporterManager, this,
213 junitReportsDirectory, testMethodPattern );
214 }
215
216 finishTestSuite( reporterManager, this );
217 }
218
219 private boolean isJUnitTest( Class c )
220 {
221 return isJunit3Test( c ) || isJunit4Test( c );
222 }
223
224 private boolean isJunit4Test( Class c )
225 {
226 return hasJunit4RunWithAnnotation( c ) || hasJunit4TestAnnotation( c );
227 }
228
229 private boolean hasJunit4RunWithAnnotation( Class c )
230 {
231 return junitRunWithAnnotation != null && c.getAnnotation( junitRunWithAnnotation ) != null;
232 }
233
234 private boolean hasJunit4TestAnnotation( Class c )
235 {
236 if ( junitTestAnnotation != null )
237 {
238 for ( Method m : c.getMethods() )
239 {
240 if ( m.getAnnotation( junitTestAnnotation ) != null )
241 {
242 return true;
243 }
244 }
245 }
246
247 return false;
248 }
249
250 private boolean isJunit3Test( Class c )
251 {
252 return junitTestClass != null && junitTestClass.isAssignableFrom( c );
253 }
254
255 private Map createJUnitOptions()
256 {
257 Map junitOptions = new HashMap( this.options );
258 junitOptions.put( "junit", Boolean.TRUE );
259 return junitOptions;
260 }
261
262
263 public void execute( String testSetName, ReporterFactory reporterManagerFactory )
264 throws TestSetFailedException
265 {
266 if ( testSets == null )
267 {
268 throw new IllegalStateException( "You must call locateTestSets before calling execute" );
269 }
270 TestNGTestSet testSet = testSets.get( testSetName );
271
272 if ( testSet == null )
273 {
274 throw new TestSetFailedException( "Unable to find test set '" + testSetName + "' in suite" );
275 }
276
277 RunListener reporter = reporterManagerFactory.createReporter();
278 ConsoleOutputCapture.startCapture( (ConsoleOutputReceiver) reporter );
279
280 startTestSuite( reporter, this );
281
282 TestNGExecutor.run( new Class[] { testSet.getTestClass() }, this.testSourceDirectory, this.options, reporter,
283 this, reportsDirectory, testMethodPattern );
284
285 finishTestSuite( reporter, this );
286 }
287
288 public static void startTestSuite( RunListener reporter, Object suite )
289 {
290 ReportEntry report = new SimpleReportEntry( suite.getClass().getName(), getSuiteName( suite ) );
291
292 try
293 {
294 reporter.testSetStarting( report );
295 }
296 catch ( ReporterException e )
297 {
298
299 }
300 }
301
302 public static void finishTestSuite( RunListener reporterManager, Object suite )
303 {
304 ReportEntry report = new SimpleReportEntry( suite.getClass().getName(), getSuiteName( suite ) );
305
306 reporterManager.testSetCompleted( report );
307 }
308
309 public String getSuiteName()
310 {
311 String result = (String) options.get( "suitename" );
312 if ( result == null )
313 {
314 result = "TestSuite";
315 }
316 return result;
317 }
318
319 private static String getSuiteName( Object suite )
320 {
321 String result;
322 if ( suite instanceof TestNGDirectoryTestSuite )
323 {
324 return ( (TestNGDirectoryTestSuite) suite ).getSuiteName();
325 }
326 else if ( suite instanceof TestNGXmlTestSuite )
327 {
328 return ( (TestNGXmlTestSuite) suite ).getSuiteName();
329 }
330 else
331 {
332 result = "TestSuite";
333 }
334
335 return result;
336 }
337
338 public Map locateTestSets( ClassLoader classLoader )
339 throws TestSetFailedException
340 {
341 if ( testSets != null )
342 {
343 throw new IllegalStateException( "You can't call locateTestSets twice" );
344 }
345 testSets = new TreeMap<String, TestNGTestSet>();
346
347 final TestsToRun scanned = scanResult.applyFilter( new NonAbstractClassFilter(), classLoader );
348
349 final TestsToRun testsToRun = runOrderCalculator.orderTestClasses( scanned );
350
351 for ( Class testClass : testsToRun )
352 {
353 TestNGTestSet testSet = new TestNGTestSet( testClass );
354
355 if ( testSets.containsKey( testSet.getName() ) )
356 {
357 throw new TestSetFailedException( "Duplicate test set '" + testSet.getName() + "'" );
358 }
359 testSets.put( testSet.getName(), testSet );
360
361 }
362
363 return Collections.unmodifiableSortedMap( testSets );
364 }
365
366 }