Chapter 15Lesson 03~185 minutes

Assertions, Failure Semantics, Retries, and Flaky-Test Control: Configuration, Design Patterns, and Trade-Offs

Retries and assertion style are policy choices with operational consequences. This lesson compares hard versus collected read-only checks, test-level versus step-level retry, blocking versus quarantine, stability thresholds, and feedback-time costs without pretending one global setting fits every suite.

Trade-offsHard assertionsQuarantineRetry scopeCapacity

Learning objectives

  • Choose between immediate hard failure and carefully collected related read-only checks.
  • Compare test-level rerun with step-level retry and identify unsafe non-idempotent cases.
  • Design quarantine as a visible, owned state rather than a mechanism for hiding red tests.
  • Balance stability thresholds, matrix breadth, and feedback latency using explicit evidence.
  • Keep retry/quarantine policy separate from WebDriver capabilities and AUT behavior.

1. Hard failure versus collecting related checks

The following table organizes the key choices and evidence for Hard failure versus collecting related checks. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Choice Use when Trade-off
Hard assertion A failed prerequisite makes later actions meaningless or unsafe. fast, clear failure; may report one defect at a time
Collect related read-only facts then assert once Several final-state facts explain one outcome. richer diagnosis; must not continue mutation after prerequisite failure
Framework soft/assert-all feature Chosen framework explicitly supports it and team understands semantics. can improve reporting; can also bury the first causal failure if overused

The mandatory path remains Python unittest, which uses hard assertions. A hand-written collector should stay small and read-only.

2. Test-level rerun versus step-level retry

The following table organizes the key choices and evidence for Test-level rerun versus step-level retry. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Retry scope Potentially appropriate Primary risk
Whole test in fresh session diagnostic experiment for a suspected transient condition extra cost; can normalize instability if automatic
Read-only wait poll expected asynchronous state transition wrong condition can still mask AUT failure
Idempotent read/API observation bounded transient infrastructure probe must have deadline and evidence
Non-idempotent UI action rarely safe without application idempotency contract duplicate order/payment/submission/state mutation
Arbitrary failed step not recommended as generic policy replays unknown partial state

3. Retry count is also feedback-time and capacity cost

If one browser attempt costs 40 seconds, “retry up to 3 times” can make a single unstable test consume roughly four attempts of browser/Grid capacity. Across a matrix, that can create queue pressure that looks like a second infrastructure problem. Model retry cost as part of capacity planning.

def worst_case_attempts(tests, browsers, initial_plus_retries):
    return tests * browsers * initial_plus_retries

print(worst_case_attempts(120, 3, 1))  # 360 clean attempts
print(worst_case_attempts(120, 3, 3))  # 1080 worst-case attempts

4. Quarantine is a workflow state with an exit condition

The following example makes the Quarantine is a workflow state with an exit condition behavior concrete. Read it with the stated assumptions, then compare its observable output or state changes with the explanation that follows.

quarantine record
- test_id: checkout.approval
- reason: timing race after component rerender
- first_seen_revision: abc123
- evidence: ci/run-4812/attempt-1
- owner: checkout-quality
- tracking_issue: QA-184
- gate_behavior: non-blocking but always executed/reported
- review_date: 2026-09-04
- exit_condition: 50 materially equivalent clean first-pass executions after fix
- max_scope: this test only

The dates/counts above are illustrative, not universal Selenium rules. The important properties are visibility, ownership, bounded scope, a root-cause record, continued execution, and a measurable exit condition.

5. Stability thresholds versus delivery velocity

A release-blocking smoke suite may demand stricter first-pass stability than a broad nightly exploratory matrix. Do not hide this difference in runner flags. Name the policy: what blocks, what warns, how pass-after-retry is reported, and which window/revision/browser combination defines the metric.

Suite class Example policy intent Evidence needed
PR smoke small, high-confidence, first-pass blocking checks first-pass result + compact artifacts
nightly browser matrix broader compatibility signal; trend flakes separately browser-specific attempt history
quarantine lane non-blocking known instability still executed owner/reason/age/current result
infrastructure canary measure runner/Grid health separately from product session startup/queue/node metrics

6. Decision table: what should you do?

The following table organizes the key choices and evidence for Decision table: what should you do?. Use it together with the surrounding prose so the rows serve as a comparison aid rather than standalone rules.

Observed situation Preferred control Why
Element becomes ready asynchronously explicit wait on correct condition synchronization belongs near state transition
Same test alternates pass/fail under controlled inputs measure + preserve evidence + root-cause retry alone cannot fix nondeterminism
Grid node occasionally unavailable classify infra and repair/route capacity do not treat as product assertion
Known flaky test blocks every release while fix is underway explicit temporary quarantine if governance allows keeps signal visible without normalizing automatic retry
Non-idempotent submit fails after click inspect state before any replay step retry can duplicate business mutation

7. Keep configuration layers distinct

  • WebDriver: browser session, capabilities, commands, waits.
  • Test framework: assertions, setup/cleanup, result statuses.
  • Retry/quarantine policy: orchestration/governance outside WebDriver semantics.
  • AUT: business idempotency, terminal states, server errors.
  • CI/Grid: attempt scheduling, capacity, artifact retention, infrastructure health.

A WebDriver capability cannot make an assertion “soft,” and a CI retry flag cannot fix a wrong locator or missing readiness condition.

8. Worked scenario: approval test intermittently times out

You have 30 controlled runs: 26 clean first-pass, 3 timeout→pass, 1 timeout→timeout. The first three flaky failures all show working at timeout and later become approved; the repeated failure shows error:dependency. Treating all four as “needs longer timeout” would merge two different causes.

  1. Fix the timing contract for the three readiness races.
  2. Track the dependency error separately as product/environment evidence.
  3. Do not keep a blanket retry once the timing contract is corrected.
  4. Re-run a controlled stability window and record first-pass results.

9. Security/privacy trade-offs in retry evidence

More attempts generate more screenshots, page sources, logs, downloads, and profiles. Artifact retention therefore expands privacy/security exposure. Sanitize synthetic fixtures, avoid secrets/PII, and configure retention by evidence value. Never solve flakiness by reusing a personal browser profile or dumping full cookies/environment variables.

10. Summary and bridge

Retry scope, assertion style, quarantine, and stability thresholds are governance decisions tied to causality, idempotency, feedback time, and capacity. Lesson 4 applies a disciplined diagnostic sequence to the failure modes that commonly defeat those policies.

Knowledge check

When is a hard assertion preferable?

Why is step-level retry especially risky for submissions?

What makes quarantine different from disabling a test?

Why does retry policy affect Grid capacity?

Can one global stability threshold fit every suite?

Next lesson

Assertions, Failure Semantics, Retries, and Flaky-Test Control: Diagnostics, Failure Modes, and Production Practices

Continue with Assertions, Failure Semantics, Retries, and Flaky-Test Control: Diagnostics, Failure Modes, and Production Practices. It builds directly on the state, evidence, and operating assumptions established here, so carry those constraints forward rather than treating the next page as an isolated topic.

Official references and version notes

Version and compatibility note

Version-sensitive behavior was rechecked against Selenium primary documentation on 2026-08-28. Mandatory examples pin Selenium Python 4.47.0 and Python 3.10+, use Python standard-library unittest, a supported locally installed Chromium-family browser with Selenium Manager, and only loopback synthetic applications. Retry/quarantine policy is deliberately modeled as test-governance logic rather than a Selenium capability. The mandatory path deliberately avoids automatic retry plugins so attempt semantics stay visible. A diagnostic retry is shown only as an explicitly coded experiment with fresh-session isolation and immutable first-attempt evidence. Quarantine thresholds/counts in examples are illustrative governance values, not Selenium defaults.

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.