fix(config): stop alwaysRun on @Before* from bypassing a configuration failure - #3453
fix(config): stop alwaysRun on @Before* from bypassing a configuration failure#3453juherr wants to merge 4 commits into
Conversation
TestInvoker already exempts a retried test method from the configuration failures of the attempt it retries, but nothing exempted that attempt's setup, so a retry whose @AfterMethod had failed ran the test method with no setup at all. The retry bit already lives in FailureContext.representsRetriedMethod, which invokeMethod reads for the test method itself; ConfigMethodArguments now carries it too, so the setup configurations of a retried invocation are exempt on the same terms as the method they set up. The teardown configurations are unchanged.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (1)
Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review. 📝 WalkthroughWalkthroughChangesConfiguration failure handling
Estimated code review effort: 2 (Simple) | ~15 minutes Merge Risk: ⚪ Minimal · up to This change documents the corrected configuration failure behavior, including skipping dependent always-run setup methods after prior setup failures. No current merge-blocking risk remains. 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Full details: Linked Issues checkExplanation The changes satisfy issue [ Full details: Docstring CoverageExplanation Docstring coverage is 11.90% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 42 functions across 10 files. (1 skipped: 1 unsupported.)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
alwaysRun is documented to mean two different things: on a @before method it runs the method regardless of the groups it belongs to, on an @after method it runs the method even if something invoked before it failed or was skipped. Since 6.9.5 a @before method got both. The fix for testng-team#420 added the four getBefore*() terms to MethodHelper.isAlwaysRun, and ConfigInvoker read that single predicate for two independent decisions: whether a configuration of a @test(enabled = false) class may still run, which is what testng-team#420 needs, and whether it may run past a failure, which it does not. So a failing @BeforeSuite -- which marks the whole suite failed under either configFailurePolicy -- was followed by every alwaysRun @BeforeTest, @BeforeClass and @BeforeMethod of the run, each setting up something no test would use, since the @test methods were skipped either way. The failure bypass now comes from MethodHelper.canBypassConfigurationFailure, which answers true only for the @after kinds, so those keep running after a failure while the group meaning of alwaysRun on a @before method and the enabled decision testng-team#420 covers are both untouched. test.configuration.issue1753 relied on the regression: its parent @BeforeMethod failed and the alwaysRun child one ran anyway. The child is now the one that fails, which keeps the failing-configuration path testng-team#1753 is about and leaves its assertions unchanged. FailingParentClassSample and ChildOfFailingParentSample cover the other way round -- the case the first hierarchy no longer reaches -- and pin that a parent @BeforeMethod which fails still contributes its attributes to the skipped result while the child one, now skipped, contributes none. Fix testng-team#1622
c584ebf to
97929dc
Compare
Fix #1622
The bug
alwaysRunis documented to mean two different things, and every@Before*/@After*annotation repeats it verbatim:Since 6.9.5 a
@Before*method got both. The fix for #420 added the fourgetBefore*()terms toMethodHelper.isAlwaysRun, andConfigInvoker.invokeConfigurationsread that one predicate for two independent decisions:@Test(enabled = false)class still run — this is what Before/AfterSuite methods may not run, when classes from suite use inheritance, and one of them has enabled=false set. #420 needs;So a failing
@BeforeSuite, which marks the whole suite failed regardless ofconfigFailurePolicy, was followed by everyalwaysRun@BeforeTest,@BeforeClassand@BeforeMethodof the run — each setting up something no test would use, since the@Testmethods were skipped either way. On the reporter's class that reads as 4 configuration failures and 0 skips where 6.9.4 reported 1 and 3.The fix
The failure bypass now comes from a separate predicate,
MethodHelper.canBypassConfigurationFailure, true only for@AfterSuite,@AfterTest,@AfterClass,@AfterMethodand@AfterGroups.isAlwaysRunkeeps its meaning and its single remaining caller, the enabled decision #420 covers, so both halves of the documented contract now have a name. The two share their phase lists rather than repeating them.This is deliberately not tied to
configFailurePolicy(the approach #1633 took): a@BeforeSuitefailure marks the suite failed whatever the policy says, and the same run reports the same invocations underSKIPand underCONTINUE. #420 is untouched, and so is the group meaning ofalwaysRunon a@Before*method.The second commit
Removing the bypass exposed a defect it had been hiding, so this PR carries it as its own commit.
TestInvoker.invokeMethodalready exempts a retried test method from the configuration failures of the attempt it retries, but nothing exempted that attempt's setup — so a retry whose@AfterMethodhad failed ran the test method with no setup at all. Until now that was only reachable for a@BeforeMethodwithoutalwaysRun, becausealwaysRunbypassed the failure and hid it.The retry bit already lives in
FailureContext.representsRetriedMethod;ConfigMethodArgumentsnow carries it, so the setup configurations of a retried invocation are exempt on the same terms as the method they set up. Teardown configurations are unchanged. It lands first so that no commit in this branch is red.Behaviour changes
alwaysRun@Before*whose parent configuration failed is reported as skipped instead of run. A suite that relied on the regression — analwaysRun@BeforeMethoddoing work after its@BeforeClassfailed — will see that method skipped.@BeforeMethodagain whether or not it saysalwaysRun.No API break.
Tests
test.configuration.issue1622.IssueTestdrives the reporter's own class — a failing@BeforeSuite,alwaysRun@BeforeTest/@BeforeClass/@BeforeMethod, a@Test, and the fouralwaysRun@After*— and asserts the exact invocation list withcontainsExactly, plus the reported configuration failure/skip/skipped-test counts. It runs the same suite twice, once with the defaultSKIPpolicy and once withCONTINUE, asserting the same list both times; that is the statement that these semantics do not depend onconfigFailurePolicy.The oracle is a static list in the sample rather than an invoked-method listener, because
ConfigInvokerfiresBEFORE_INVOCATIONon the skip path too and a listener could not tell "ran" from "skipped".Measured, before → after (identical under both policies):
which is what 6.9.4 reported.
test.configuration.issue1753relied on the regression: its parent@BeforeMethodfailed and thealwaysRunchild one ran anyway. The child is now the one that fails, which keeps the failing-configuration path #1753 is about and leaves its assertions unchanged.Since that flips which method fails, a second hierarchy —
FailingParentClassSample/ChildOfFailingParentSample— covers the case the first one no longer reaches: a parent@BeforeMethodthat fails still contributes its attributes to the skipped result, while the child one, now skipped, contributes none. Measured keys on the skipped result:containsOnlyKeysmakes that exact, so it is also a guard on this PR: with thealwaysRunbypass restored,ChildOfFailingParentSample-childClassBeforeMethodreappears and the assertion fails.Validation
./gradlew buildis green on both commits — 0 failures, 0 errors across every result file, on the retry commit alone and on the branch head.Red → green → red was checked on the final code: with the
canBypassConfigurationFailureterm reverted to!alwaysRunand the test kept,test.configuration.issue1622.IssueTestfails withbut some elements were not expected: ["beforeTest", "beforeClass", "beforeMethod"]under both policies; restoring it turns it green.Summary by CodeRabbit
Bug Fixes
New Features
Documentation