Skip to content

Commit

Permalink
#2734 keep the initial order of listeners (#2737)
Browse files Browse the repository at this point in the history
* #2734 keep the initial order of listeners

We need to run listeners at the same order in which they were declared in @listeners({First.class, Second.class, Third.class})
  • Loading branch information
asolntsev committed Mar 16, 2022
1 parent 0438740 commit e9a6c4f
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.txt
Expand Up @@ -5,6 +5,7 @@ Fixed: assertEqualsNoOrder for Collection and Iterators size check was missing (
Fixed: GITHUB-2709: Testnames not working together with suites in suite (Martin Aldrin)
Fixed: GITHUB-2704: IHookable and IConfigurable callback discrepancy (Krishnan Mahadevan)
Fixed: GITHUB-2637: Upgrade to JDK11 as the minimum JDK requirements (Krishnan Mahadevan)
Fixed: GITHUB-2734: Keep the initial order of listeners (Andrei Solntsev)

7.5
Fixed: GITHUB-2701: Bump gradle version to 7.3.3 to support java17 build (ZhangJian He)
Expand Down
2 changes: 1 addition & 1 deletion testng-core/src/main/java/org/testng/TestRunner.java
Expand Up @@ -345,7 +345,7 @@ private void initListeners() {
// Find all the listener factories and collect all the listeners requested in a
// @Listeners annotation.
//
Set<Class<? extends ITestNGListener>> listenerClasses = Sets.newHashSet();
Set<Class<? extends ITestNGListener>> listenerClasses = Sets.newLinkedHashSet();
Class<? extends ITestNGListenerFactory> listenerFactoryClass = null;

for (IClass cls : getTestClasses()) {
Expand Down
94 changes: 94 additions & 0 deletions testng-core/src/test/java/org/testng/TestRunnerTest.java
@@ -0,0 +1,94 @@
package org.testng;

import static java.util.Collections.emptyList;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.List;
import java.util.stream.Collectors;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;
import org.testng.internal.Configuration;
import org.testng.internal.IConfiguration;
import org.testng.internal.objects.DefaultTestObjectFactory;
import org.testng.xml.XmlClass;
import org.testng.xml.XmlSuite;
import org.testng.xml.XmlTest;

public class TestRunnerTest {
@Test
public void listenersShouldBeAppliedInDeclarationOrder_one() {
TestRunner testRunner = createTestRunner(TestWithOneListener.class);

List<IConfigurationListener> configurationListeners = testRunner.getConfigurationListeners();

assertThat(classesOf(configurationListeners, 1)).containsExactly(FooListener.class);
}

@Test
public void listenersShouldBeAppliedInDeclarationOrder_two() {
TestRunner testRunner = createTestRunner(TestWithTwoListeners.class);

List<IConfigurationListener> configurationListeners = testRunner.getConfigurationListeners();

assertThat(classesOf(configurationListeners, 2))
.containsExactly(FooListener.class, BarListener.class);
}

@Test
public void listenersShouldBeAppliedInDeclarationOrder_three() {
TestRunner testRunner = createTestRunner(TestWithThreeListeners.class);

List<IConfigurationListener> configurationListeners = testRunner.getConfigurationListeners();

assertThat(classesOf(configurationListeners, 3))
.containsExactly(FooListener.class, BarListener.class, ZooListener.class);
}

@Listeners(FooListener.class)
public static class TestWithOneListener {
@Test
public void some() {}
}

@Listeners({FooListener.class, BarListener.class})
public static class TestWithTwoListeners {
@BeforeMethod
public void setup() {}

@Test
public void some() {}
}

@Listeners({FooListener.class, BarListener.class, ZooListener.class})
public static class TestWithThreeListeners {
@Test
public void some() {}
}

public static class FooListener implements IConfigurationListener {}

public static class BarListener implements IConfigurationListener {}

public static class ZooListener implements IConfigurationListener {}

private <T> List<Class<?>> classesOf(List<T> values, int limit) {
return values.stream().limit(limit).map(Object::getClass).collect(Collectors.toList());
}

private TestRunner createTestRunner(Class<?> testClass) {
IConfiguration configuration = new Configuration();
configuration.setObjectFactory(new DefaultTestObjectFactory());
XmlSuite xmlSuite = new XmlSuite();
XmlTest xmlTest = new XmlTest(xmlSuite);
xmlSuite.addTest(xmlTest);
XmlClass xmlClass = new XmlClass(testClass.getName());
xmlTest.getXmlClasses().add(xmlClass);
String outputDir = "build/reports/tests/test";
ITestRunnerFactory factory =
(suite, test, listeners, classListeners) ->
new TestRunner(configuration, suite, test, false, listeners, classListeners);
ISuite suite = new SuiteRunner(configuration, xmlSuite, outputDir, factory, (o1, o2) -> 0);
return factory.newTestRunner(suite, xmlTest, emptyList(), emptyList());
}
}
6 changes: 6 additions & 0 deletions testng-core/src/test/resources/testng.xml
Expand Up @@ -927,6 +927,12 @@
</classes>
</test>

<test name="TestRunner_unit_tests">
<classes>
<class name="org.testng.TestRunnerTest"/>
</classes>
</test>

<!--This test depends on System properties. So its intentionally being run at the end
because the toggling of the system property will affect other tests -->
<test name = "RunAtLast">
Expand Down

0 comments on commit e9a6c4f

Please sign in to comment.