Skip to content

Mix test parameters into the per-test :rand seed - #15869

Merged
josevalim merged 1 commit into
elixir-lang:mainfrom
jechol:fix/parameterize-rand-seed
Sep 8, 2026
Merged

josevalim merged 1 commit into
elixir-lang:mainfrom
jechol:fix/parameterize-rand-seed

Conversation

@jechol

@jechol jechol commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

ExUnit seeds each test process with {phash2(module), phash2(name), suite_seed}. parameterize re-runs the module once per parameter set, changing only test.parameters and leaving test.name as is, so every parameterized run of a test starts from the same :rand state and draws the same random sequence.

use ExUnit.Case, parameterize: for(n <- 1..3, do: %{n: n})

test "first :rand value", %{n: n} do
  IO.puts("parameter #{n}: #{:rand.uniform(1_000_000_000)}")
end
parameter 1: 297992752
parameter 2: 297992752
parameter 3: 297992752

In practice this bites any test helper that generates random unique values. With Ecto's SQL sandbox, every parameter set inserts the same random email, and the unique index turns that into lock waits between the concurrent transactions, so the parameterized tests end up running one after another.

This PR hashes the parameters together with the name when they are present, so each parameter set gets its own seed. Tests without parameters keep their previous seed, so existing --seed reproductions are unaffected and the constants in the existing "seed is predictable" test still pass. short_hash/3 in the same file already takes this approach for tmp_dir paths.

The added test fails on the current runner and passes with the change.

Reproduction: https://github.com/jechol/repro-exunit-parameterize-seed

The code was written with the help of an AI coding agent and reviewed by me; see the Assisted-by tag in the commit.

ExUnit seeds each test process with {phash2(module), phash2(name), seed}.
parameterize re-runs the module per parameter set without changing the
test name, so every parameter set of a test started from the same :rand
state and drew the same random sequence.

Hash the parameters together with the name when they are present. Tests
without parameters keep their previous seed, so existing --seed
reproductions are unaffected.

Assisted-by: Claude Code:claude-fable-5-1
Signed-off-by: Jechol Lee <mr.jechol@gmail.com>
@josevalim
josevalim merged commit 360ed75 into elixir-lang:main Sep 8, 2026
15 checks passed
@josevalim

Copy link
Copy Markdown
Member

💚 💙 💜 💛 ❤️

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

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants