Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow OnAfterClass listeners to run after AfterClass Configuration Methods #2865

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
Current
Fixed: GITHUB-2796: Option for onAfterClass to run after @AfterClass
Fixed: GITHUB-2857: XmlTest index is not set for test suites invoked with YAML

7.7.1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public final class RuntimeBehavior {
public static final String STRICTLY_HONOUR_PARALLEL_MODE = "testng.strict.parallel";
public static final String TESTNG_DEFAULT_VERBOSE = "testng.default.verbose";
public static final String IGNORE_CALLBACK_INVOCATION_SKIPS = "testng.ignore.callback.skip";
public static final String SYMMETRIC_LISTENER_EXECUTION = "testng.listener.execution.symmetric";

private RuntimeBehavior() {}

Expand Down Expand Up @@ -132,4 +133,17 @@ public static boolean enforceThreadAffinity() {
public static int getDefaultVerboseLevel() {
return Integer.getInteger(TESTNG_DEFAULT_VERBOSE, 1);
}

/**
* @return - <code>true</code> if we would like to invoke AfterClass methods symmetrically to
* BeforeClass. When true, order is:
* <ol>
* <li>Class @afterClass methods
* <li>Listener onAfterClass methods
* </ol>
* When false, order is reversed.
*/
public static boolean useSymmetricListenerExecution() {
return Boolean.parseBoolean(System.getProperty(SYMMETRIC_LISTENER_EXECUTION, "false"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -207,9 +207,16 @@ protected void invokeAfterClassMethods(ITestClass testClass, IMethodInstance mi)
invokeInstances.add(inst);
}

for (IClassListener listener : m_listeners) {
listener.onAfterClass(testClass);
if (RuntimeBehavior.useSymmetricListenerExecution()) {
invokeAfterClassConfigurations(testClass, invokeInstances);
invokeListenersOnAfterClass(testClass, m_listeners);
} else {
invokeListenersOnAfterClass(testClass, m_listeners);
invokeAfterClassConfigurations(testClass, invokeInstances);
}
}

private void invokeAfterClassConfigurations(ITestClass testClass, List<Object> invokeInstances) {
for (Object invokeInstance : invokeInstances) {
ConfigMethodArguments attributes =
new Builder()
Expand All @@ -223,6 +230,12 @@ protected void invokeAfterClassMethods(ITestClass testClass, IMethodInstance mi)
}
}

private void invokeListenersOnAfterClass(ITestClass testClass, List<IClassListener> listeners) {
for (IClassListener listener : listeners) {
listener.onAfterClass(testClass);
}
}

protected int indexOf(ITestNGMethod tm, ITestNGMethod[] allTestMethods) {
for (int i = 0; i < allTestMethods.length; i++) {
if (allTestMethods[i] == tm) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.assertj.core.api.Assertions;
import org.testng.TestNG;
import org.testng.annotations.Test;
import org.testng.internal.RuntimeBehavior;
import test.SimpleBaseTest;
import test.listeners.issue1952.TestclassSample;

Expand Down Expand Up @@ -462,6 +463,102 @@ public void testOrderHasOnlyFailedMethodWithRetryMechanism() {
runTest(expected, SimpleTestClassWithFailedMethodHasRetryAnalyzer.class, true);
}

@Test(description = "Test Configuration/Listener order NOT using symmetric listener execution")
public void testOrderForNonSymmetricOnAfterClass() {
List<String> nonSymmetricExpected =
Arrays.asList(
IEXECUTIONLISTENER_ON_EXECUTION_START,
IALTERSUITELISTENER_ALTER,
IANNOTATIONTRANSFORMER_TRANSFORM_3_ARGS,
IANNOTATIONTRANSFORMER_TRANSFORM_4_ARGS,
ISUITELISTENER_ON_START,
ITESTLISTENER_ON_START_TEST_TAG,
METHODINTERCEPTOR_INTERCEPT,
METHODINTERCEPTOR_INTERCEPT,
// onBeforeClass
ICLASSLISTENER_ON_BEFORE_CLASS,
// @beforeClass
ICONFIGURATIONLISTENER_BEFORE_CONFIGURATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ICONFIGURATIONLISTENER_ON_CONFIGURATION_SUCCESS,
// test method
ITESTLISTENER_ON_START_TEST_METHOD,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ITESTLISTENER_ON_TEST_SUCCESS_TEST_METHOD,
// onAfterClass
ICLASSLISTENER_ON_AFTER_CLASS,
// @afterClass
ICONFIGURATIONLISTENER_BEFORE_CONFIGURATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ICONFIGURATIONLISTENER_ON_CONFIGURATION_SUCCESS,
IEXECUTION_VISUALISER_CONSUME_DOT_DEFINITION,
ITESTLISTENER_ON_FINISH_TEST_TAG,
ISUITELISTENER_ON_FINISH,
IREPORTER_GENERATE_REPORT,
IEXECUTIONLISTENER_ON_EXECUTION_FINISH);
runTest(nonSymmetricExpected, SimpleTestClassWithBeforeAndAfterClass.class);
}

@Test(description = "Test Configuration/Listener order using symmetric listener execution")
public void testOrderForSymmetricOnAfterClass() {
List<String> symmetricExpected =
Arrays.asList(
IEXECUTIONLISTENER_ON_EXECUTION_START,
IALTERSUITELISTENER_ALTER,
IANNOTATIONTRANSFORMER_TRANSFORM_3_ARGS,
IANNOTATIONTRANSFORMER_TRANSFORM_4_ARGS,
ISUITELISTENER_ON_START,
ITESTLISTENER_ON_START_TEST_TAG,
METHODINTERCEPTOR_INTERCEPT,
METHODINTERCEPTOR_INTERCEPT,
// onBeforeClass
ICLASSLISTENER_ON_BEFORE_CLASS,
// @beforeClass
ICONFIGURATIONLISTENER_BEFORE_CONFIGURATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ICONFIGURATIONLISTENER_ON_CONFIGURATION_SUCCESS,
// test method
ITESTLISTENER_ON_START_TEST_METHOD,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ITESTLISTENER_ON_TEST_SUCCESS_TEST_METHOD,
// @afterClass
ICONFIGURATIONLISTENER_BEFORE_CONFIGURATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION,
IINVOKEDMETHODLISTENER_BEFORE_INVOCATION_WITH_CONTEXT,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION,
IINVOKEDMETHODLISTENER_AFTER_INVOCATION_WITH_CONTEXT,
ICONFIGURATIONLISTENER_ON_CONFIGURATION_SUCCESS,
// onAfterClass
ICLASSLISTENER_ON_AFTER_CLASS,
IEXECUTION_VISUALISER_CONSUME_DOT_DEFINITION,
ITESTLISTENER_ON_FINISH_TEST_TAG,
ISUITELISTENER_ON_FINISH,
IREPORTER_GENERATE_REPORT,
IEXECUTIONLISTENER_ON_EXECUTION_FINISH);

try {
System.setProperty(RuntimeBehavior.SYMMETRIC_LISTENER_EXECUTION, Boolean.TRUE.toString());
runTest(symmetricExpected, SimpleTestClassWithBeforeAndAfterClass.class);
} finally {
System.setProperty(RuntimeBehavior.SYMMETRIC_LISTENER_EXECUTION, Boolean.FALSE.toString());
}
}

private static void runTest(List<String> expected, Class<?> clazz) {
runTest(expected, clazz, false);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package test.listeners.ordering;

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

public class SimpleTestClassWithBeforeAndAfterClass {
@BeforeClass
public void beforeClass() {}

@Test
public void testWillPass() {}

@AfterClass
public void afterClass() {}
}