Flaky test not reproduced by RSpec --bisect: diagnosing non‑order‑dependent failures
0 reputation · 10 Jun 2024, 13:58 UTC
0 reputation · 10 Jun 2024, 13:58 UTC
When a test suite exhibits intermittent failures, developers often turn to RSpec’s --bisect flag to find the minimal set of examples that reproduces the problem under a fixed random seed.
The goal is to decide whether the observed flakiness stems from order‑dependent state leakage or from other sources such as timing, concurrency, or external service calls, given that --bisect only isolates failures that are reproducible when the suite order is changed.
Because --bisect assumes determinism under a pinned seed and requires the suite to be runnable non‑interactively, it cannot distinguish ordering‑related flakiness from flakiness caused by external factors, leaving the diagnostic strategy to the developer.
What indicators suggest a failure is not order‑dependent? How can a team differentiate ordering‑related flakiness from timing or concurrency‑related flakiness without built‑in RSpec support? Are there complementary approaches or configuration options that could help surface the root cause class?
31775 reputation · 10 Jun 2024, 22:08 UTC
If --bisect fails to reproduce the failure, the most likely explanation is that the flake is not order-dependent. --bisect works by permuting example order under a pinned seed to find a minimal reproducing set — it can only isolate failures that deterministically appear for some ordering. A failure that appears and disappears under the same seed is, by definition, outside what bisect can find. One caveat before concluding anything: a passing bisect run does not prove order-independence; it only shows the failure wasn't reproduced under the orders bisect explored. Very slow suites also make bisect impractical even for genuinely order-dependent bugs.
Look at the failure message and context first. Non-order-dependent flakes typically show:
parallel_tests), where cross-process contention on the database or ports mimics order dependence.The decisive test is to run the failing example alone, with the recorded seed, many times. Identical order plus intermittent failure means ordering is not the variable:
for i in $(seq 1 100); do
bundle exec rspec --seed 12345 spec/models/thing_spec.rb \
|| echo "FAILED on iteration $i"
done
Interpretation:
Once you have a stochastic single-example failure, narrow the class with controlled elimination:
Rails.application.config, ENV changes, or an incomplete DatabaseCleaner/transactional-fixtures setup.rspec --only-failures (with a persisted status file) and rspec-retry help quantify flake rate and triage, but treat retry as a measurement tool, not a fix — it masks root causes. RSpec has no built-in timing-flake detector; the loop-plus-elimination approach above is the standard substitute.
This guidance assumes a reasonably current RSpec 3.x and a suite that runs non-interactively. The one detail that would change the recommendation: does the failing example pass when run alone? If yes, invest in seed-stable full-suite reruns and state-leak auditing; if no, skip bisect entirely and go straight to the timing/external-dependency elimination steps.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.