7
7
import java .util .List ;
8
8
import java .util .Map ;
9
9
import java .util .Objects ;
10
+ import java .util .Optional ;
10
11
import java .util .Set ;
11
12
import java .util .concurrent .ConcurrentHashMap ;
12
13
import java .util .concurrent .atomic .AtomicReference ;
@@ -325,6 +326,7 @@ private static Graph<ITestNGMethod> topologicalSort(
325
326
Map <Object , List <ITestNGMethod >> testInstances = sortMethodsByInstance (methods );
326
327
327
328
XmlTest xmlTest = null ;
329
+
328
330
for (ITestNGMethod m : methods ) {
329
331
if (xmlTest == null ) {
330
332
xmlTest = m .getXmlTest ();
@@ -358,13 +360,12 @@ private static Graph<ITestNGMethod> topologicalSort(
358
360
!(m .isBeforeGroupsConfiguration () || m .isAfterGroupsConfiguration ());
359
361
boolean isGroupAgnosticConfigMethod = !m .isTest () && anyConfigExceptGroupConfigs ;
360
362
if (isGroupAgnosticConfigMethod ) {
361
- String [] groupsDependedUpon = m .getGroupsDependedUpon ();
362
- if (groupsDependedUpon .length > 0 ) {
363
- for (String group : groupsDependedUpon ) {
364
- ITestNGMethod [] methodsThatBelongToGroup =
365
- MethodGroupsHelper .findMethodsThatBelongToGroup (m , methods , group );
366
- predecessors .addAll (Arrays .asList (methodsThatBelongToGroup ));
367
- }
363
+ String [] groupsDependedUpon =
364
+ Optional .ofNullable (m .getGroupsDependedUpon ()).orElse (new String [0 ]);
365
+ for (String group : groupsDependedUpon ) {
366
+ ITestNGMethod [] methodsThatBelongToGroup =
367
+ MethodGroupsHelper .findMethodsThatBelongToGroup (m , methods , group );
368
+ predecessors .addAll (Arrays .asList (methodsThatBelongToGroup ));
368
369
}
369
370
}
370
371
@@ -380,6 +381,31 @@ private static Graph<ITestNGMethod> topologicalSort(
380
381
return result ;
381
382
}
382
383
384
+ private static Comparator <ITestNGMethod > bubbleUpIndependentMethodsFirst () {
385
+ return (a , b ) -> {
386
+ boolean aIsIndependent = isIndependent (a );
387
+ boolean bIsIndependent = isIndependent (b );
388
+ if (aIsIndependent && bIsIndependent ) {
389
+ // Both a and b are independent methods. So treat them as equal.
390
+ return 0 ;
391
+ }
392
+ if (aIsIndependent ) {
393
+ // First method is independent. So a should come before b.
394
+ return -1 ;
395
+ }
396
+ if (bIsIndependent ) {
397
+ // Second method is independent. So a should come after b.
398
+ return 1 ;
399
+ }
400
+ // Both a and b are dependent methods. So treat them as equal
401
+ return 0 ;
402
+ };
403
+ }
404
+
405
+ private static boolean isIndependent (ITestNGMethod tm ) {
406
+ return tm .getMethodsDependedUpon ().length == 0 && tm .getGroupsDependedUpon ().length == 0 ;
407
+ }
408
+
383
409
/**
384
410
* This method is used to create a map of test instances and their associated method(s) . Used to
385
411
* decrease the scope to only a methods instance when trying to find method dependencies.
@@ -442,6 +468,18 @@ private static List<ITestNGMethod> sortMethods(
442
468
|| m .isBeforeSuiteConfiguration ()
443
469
|| m .isBeforeTestConfiguration ();
444
470
MethodInheritance .fixMethodInheritance (allMethodsArray , before );
471
+
472
+ // In-case the user has ended up using "dependsOn" on configurations, then sometimes
473
+ // TestNG ends up finding the configuration methods in such a way that, it can cause
474
+ // un-expected failures. This usually happens due to the fully qualified method names
475
+ // acting up. So let's re-order the methods such that, the independent configurations always
476
+ // bubble up to the top and the ones that have dependencies get pushed to the bottom.
477
+ // That way, when we do a topologicalSort sort, the logic would work fine.
478
+
479
+ allMethodsArray =
480
+ Arrays .stream (allMethodsArray )
481
+ .sorted (bubbleUpIndependentMethodsFirst ())
482
+ .toArray (ITestNGMethod []::new );
445
483
}
446
484
447
485
topologicalSort (allMethodsArray , sl , pl , comparator );
0 commit comments