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

BUG: Parameter alwaysRun=true for before-methods forces execution of those methods #1622

Open
1 of 7 tasks
kool79 opened this issue Nov 21, 2017 · 15 comments · May be fixed by #1633 or #2198
Open
1 of 7 tasks

BUG: Parameter alwaysRun=true for before-methods forces execution of those methods #1622

kool79 opened this issue Nov 21, 2017 · 15 comments · May be fixed by #1633 or #2198

Comments

@kool79
Copy link

kool79 commented Nov 21, 2017

TestNG Version

6.12, 6.11, ...

Expected behavior

According to official documentation parameter 'alwaysRun' for before-methods is used only to enable/disable filtering by groups. It must not force method execution if higher-level configuration(s) failed.
In any case alwaysRun should not be used both for filtering and for execution forcing

Actual behavior

BeforeTest/BeforeClass/BeforeMethod with (alwaysRun = true) is executed when higher - level configuration failed (BeforeSuite/BeforeTest/BeforeClass)

Is the issue reproductible on runner?

  • Shell
  • Maven
  • Gradle
  • Ant
  • Eclipse
  • IntelliJ
  • NetBeans

Test case sample

Please, share the test case (as small as possible) which shows the issue

public class AlwaysRunTests {

	@BeforeSuite
	public void failedBeforeSuite() {
		System.out.println("I'm beforeSuite. I should be alone in console log. Going to fail...");
		throw new RuntimeException();
	}

	@BeforeTest(alwaysRun = true)
	public void beforeTest() {
		System.out.println("BUG: I'm beforeTest and I was invoked (((( ");
		throw new RuntimeException();
	}

	@BeforeClass(alwaysRun = true)
	public void beforeClass() {
		System.out.println("BUG: I'm beforeClass and I was invoked (((( ");
		throw new RuntimeException();
	}

	@BeforeMethod(alwaysRun = true)
	public void beforeMethod() {
		System.out.println("BUG: I'm beforeMethod and I was invoked (((( ");
		throw new RuntimeException();
	}

	@Test
	public void testMethod() {
		System.out.println("I'm testMethod");
	}
}

Console output (stacktraces truncated):

I'm beforeSuite. I should be alone in console log. Going to fail...

java.lang.RuntimeException
	at qa.ok.testng.AlwaysRunTests.failedBeforeSuite(AlwaysRunTests.java:14)

BUG: I'm beforeTest and I was invoked (((( 

java.lang.RuntimeException
	at qa.ok.testng.AlwaysRunTests.beforeTest(AlwaysRunTests.java:21)

BUG: I'm beforeClass and I was invoked (((( 

java.lang.RuntimeException
	at qa.ok.testng.AlwaysRunTests.beforeClass(AlwaysRunTests.java:28)

BUG: I'm beforeMethod and I was invoked (((( 

java.lang.RuntimeException
	at qa.ok.testng.AlwaysRunTests.beforeMethod(AlwaysRunTests.java:35)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:108)
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:523)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:224)
	at org.testng.internal.Invoker.invokeMethod(Invoker.java:599)
	at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:877)
	at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1201)
	at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
	at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
	at org.testng.TestRunner.privateRun(TestRunner.java:776)
	at org.testng.TestRunner.run(TestRunner.java:634)
	at org.testng.SuiteRunner.runTest(SuiteRunner.java:425)
	at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:420)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:385)
	at org.testng.SuiteRunner.run(SuiteRunner.java:334)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1318)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1243)
	at org.testng.TestNG.runSuites(TestNG.java:1161)
	at org.testng.TestNG.run(TestNG.java:1129)
	at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
	at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)

Test ignored.
===============================================
Default Suite
Total tests run: 1, Failures: 0, Skips: 1
Configuration Failures: 4, Skips: 0
===============================================
@kool79 kool79 changed the title Parameter alwaysRun=true for before - methods forces BUG: Parameter alwaysRun=true for before-methods forces execution of those methods Nov 21, 2017
@juherr
Copy link
Member

juherr commented Nov 27, 2017

Thanks for the report.

How do you run the class?

Then, there are 2 interpretations:

  • no group means the default no-group, and the behavior is the expected one (before the no-group)
  • no group is the default group, and the current behavior is an issue.

Related to #1574
Ping @krmahadevan

@kool79
Copy link
Author

kool79 commented Nov 27, 2017

no group is no group.
I run this without any groups defined, with default IntelliJ IDEA runner both from context menu on test-method and from context menu on testng.xml:

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="my-suite">
	<test name ="my-test">
		<packages>
			<package name="qa.ok.testng.*"/>
		</packages>
	</test>
</suite>

(package qa.ok.testng.* contains only one class "AlwaysRunTests" listed in my prev. comment)
No other settings/listeners/etc are present.
I've attached zip with pom, java and testng.xml:
always-run-test.zip

@juherr
Copy link
Member

juherr commented Nov 27, 2017

I reword:

no group is the default group

Your current suite will run all tests in the package, right?
And not just tests without group.

BTW, it is debatable and we can only quick fix regression for the moment.

@kool79
Copy link
Author

kool79 commented Nov 27, 2017

Your current suite will run all tests in the package, right?

Yes. I understand. You mean my tests-list can also have some tests with groups so this can be the reason why Before-methods invoked.
But I don't want to run those methods if any of the 'parent' configurations failed.
In any case current behavior does not corresponds to documentation. I don't know if it is the documentation bug or it the bug in code which was introduced after documentation was published.
In documentation the parameter "alwaysRun" has 2 different meanings for before- and after- methods :

  • For before methods (beforeSuite, beforeTest, beforeTestClass and beforeTestMethod, but not beforeGroups): If set to true, this configuration method will be run regardless of what groups it belongs to.
  • For after methods (afterSuite, afterClass, ...): If set to true, this configuration method will be run even if one or more methods invoked previously failed or was skipped.

So first is about groups (always run regardless on group) and second - about failed/skipped (alwaysRun regardless on failed/skipped). But currently 'alwaysRun' for before-methods includes behavior for after-methods:
when set to true:

  1. configuration method will be run even if one or more methods invoked previously failed or was skipped AND
  2. configuration method will be run regardless of what groups it belongs to.

@kool79
Copy link
Author

kool79 commented Nov 27, 2017

I've found this bug was introduced in testng-6.9.5 when fixing #420
Below the log for v6.9.4 (note that no other before methods were invoked except before-suite):

  D:\dev\AC\git\test-testng\testng.xml
I'm beforeSuite. I should be alone in console log. Going to fail...

java.lang.RuntimeException
	at qa.ok.testng.AlwaysRunTests.failedBeforeSuite(AlwaysRunTests.java:14)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:85)
	at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:517)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:213)
	at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:140)
	at org.testng.SuiteRunner.privateRun(SuiteRunner.java:296)
	at org.testng.SuiteRunner.run(SuiteRunner.java:259)
	at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
	at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
	at org.testng.TestNG.runSuitesSequentially(TestNG.java:1199)
	at org.testng.TestNG.runSuitesLocally(TestNG.java:1124)
	at org.testng.TestNG.run(TestNG.java:1032)
	at org.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:72)
	at org.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:123)
Test ignored.
===============================================
my-suite
Total tests run: 1, Failures: 0, Skips: 1
Configuration Failures: 1, Skips: 3
===============================================

@juherr
Copy link
Member

juherr commented Nov 27, 2017

Ok, thanks for digging 👍

@krmahadevan
Copy link
Member

@juherr - I am not sure how to go about fixing this because :

I am not able to figure out how to determine if the user ran with group filtering or if the user ran tests as is. The reason I say this is because a user may have applied a method selector (either as implementation or as a beanshell expression) to filter methods.

So if I cannot determine if the tests are being run by applying groups, I will not be able to determine if alwaysRun=true should be considered or not.

@kool79
Copy link
Author

kool79 commented Dec 6, 2017

Guys, sorry but I just want to prevent breaking changes in testng, so will try to explain my opinion:
Before testng v6.9.5 parameter alwaysRun had very different meaning in @Before- and @After- methods. Below I tried to describe behavior for that version (based on official testng documentation, javadocs and implementation):

  • In context of @BeforeSuite, @BeforeTest, @BeforeClass, @BeforeMethod :
    schedule this method for execution regardless to which group it belongs / does not belong (of cause if corresponding @Tests were scheduled)
    Please note: (by implementation up to 6.9.5):
    -- method will be skipped if any parent or preceding configurations failed.
    -- this behavior does not depend on config-failure-policy

  • In context of @AfterSuite, @AfterTest, @AfterClass, @AfterMethod :
    (from javadoc and official documentation): configuration method will be run even if one or more methods invoked previously failed or was skipped

  • In context of @Test:
    (from javadoc): run test-method even if it depends on a method that failed. This attribute ignored if test doesn't depend on any method or group.
    Please note:
    -- test-method will be skipped (will not run) if it depends on skipped methods.
    -- test-method will be skipped in every case when any of parent configurations failed.

Last note is very impotent. It means: even when if you force to execute @BeforeMethod after @BeforeClass was failed , all the methods which belongs to class will be skipped. So why we need to force execution of @BeforeMethod if test ignored in any way???

I think this behavior ( v6.9.5) should be saved because it was well-designed by @cbeust and it have meaning. There are no reasonable situations in testing when you should continue to execute 'child' prerequisites after 'parent' failed.

@krmahadevan, If I understand properly from PR 9d5e6d7, you want to force execution for before-methods only when configfailurepolicy = continue. Please use SRP principle for parameters in testng. Currently (v13.1) configfailurepolicy used to avoid multiple execution of the same configuration method. (Same means: method with concrete signature which belongs to concrete instance) Please don't use this parameter for any other purpose. This will break compatibility and will make process of testng configuration ugly.

Finally:
IMHO to fix current issue you should revert changes which were made in scope of #420 (328620f) - it was wrong fix. Maybe it fixed behavior in particular case but it does not fix root cause. I'm almost sure that issue #420 can be reproduced with or without alwaysRun on @BeforeSuite

@juherr
Copy link
Member

juherr commented Dec 6, 2017

@kool79 It looks you have a good knowledge of the issue. Maybe you can propose a pull request with the fix?

@krmahadevan
Copy link
Member

Sorry.. by mistake clicked the wrong button.

@ntulele
Copy link

ntulele commented Mar 13, 2018

@kool79 Just want to "upvote" this issue: I agree with your assessment, and find the current behavior frustrating. Given your extensive knowledge of the issue, would you mind trying to submit a fix? (i.e., reverting #420 but also proposing a better fix for that?)

@aTan-aka-Xellos
Copy link

+1, our team affected by this issue.
Is there any work-around to force skip of before/after methods by manipulation with IContext for example?

@juherr juherr added this to the 7.0 milestone Aug 29, 2018
krmahadevan added a commit to krmahadevan/testng that referenced this issue Sep 2, 2018
@hg0605
Copy link

hg0605 commented Oct 29, 2018

any workaround for this issue?

@krmahadevan
Copy link
Member

@hg0605 - No there aren't any workarounds for this issue at the moment.

@cnealaccela
Copy link

Any update on this? We want to terminate the suite at the BeforeSuite level, but are noticing all the beforeMethods are still running.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment