RSpec 3.x Global Hook Execution Order with Randomized Seed Values
0 reputation · 01 Nov 2025, 01:29 UTC
0 reputation · 01 Nov 2025, 01:29 UTC
RSpec 3.x utilizes a centralized RSpec.configure block to manage global hooks and expectations. In complex test suites with deeply nested context blocks, the framework executes hooks in a specific hierarchy: global hooks, followed by group-level hooks, and finally example-level hooks.
When the --order random flag is applied, RSpec randomizes the execution sequence of examples to prevent order-dependency. However, the interaction between this randomization and the deterministic execution of global hooks within nested contexts can create uncertainty regarding state isolation.
If a global before(:each) hook modifies a shared resource that is also manipulated within a nested context, the resulting state depends on the specific seed value used for that run.
34775 reputation · 01 Nov 2025, 07:17 UTC
No — the --order random flag does not affect hook priority at all. Randomization shuffles which example runs next; it never changes which hooks run around each example. For every single example, regardless of seed, RSpec 3.x invokes hooks in the same fixed sequence:
before(:each) hooks (from RSpec.configure), in the order they were definedbefore(:each) hooks, outermost context first, then nested contextsafter(:each) hooks, innermost context firstafter(:each) hooks, in reverse definition orderNested contexts only append their hooks to this sequence. They cannot jump ahead of a global hook, and no seed value can change that.
The deterministic part is the hook order per example. What the seed does control is the sequence of examples themselves. So if your global before(:each) mutates a shared resource (a class variable, a singleton, a temp directory, a database row that survives cleanup), and a nested context's hook also mutates it, the final state of that resource at any given example depends on which examples ran before it — and that is exactly what the seed determines.
In other words: the hook hierarchy is stable, but shared mutable state accumulates across examples, and the accumulation path is seed-dependent. This is the classic order-dependency leak that random ordering exists to expose, not a hook-ordering problem.
Internally, RSpec builds each example's hook chain from its example group hierarchy at definition time. When the random orderer runs, it only reorders the list of examples; each example still carries its full, precomputed hook chain (global → outer group → inner group). Shuffling examples across different nested contexts therefore has no effect on the chain attached to each one.
A minimal experiment confirms the behavior in about a minute:
RSpec.configure do |c|
c.before(:each) { puts "GLOBAL before" }
c.after(:each) { puts "GLOBAL after" }
end
RSpec.describe "outer" do
before(:each) { puts "OUTER before" }
context "nested" do
before(:each) { puts "NESTED before" }
it("example A") { puts "example A" }
it("example B") { puts "example B" }
end
it("example C") { puts "example C" }
end
Run it twice with different seeds:
rspec --order random --seed 1234
rspec --order random --seed 9999
You should see the example order change between runs, while every example is always wrapped in the same GLOBAL before → OUTER before → NESTED before → … → GLOBAL after sequence.
If a global before(:each) touches shared state, make that hook fully reset the resource rather than incrementally modify it — a reset makes the seed irrelevant. If the state genuinely needs to differ per context, move the mutation into let or the specific group's hook instead of the global one. And always record the seed (--seed is printed on every random run) so a failure can be reproduced exactly.
One caveat worth flagging: this describes RSpec 3.x behavior, which has been stable across the 3.x line. If you are on an older 2.x suite or a pre-release of a future major version, re-run the verification snippet above against your exact version before relying on it.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.