Skip to content

Commit 5175cc6

Browse files
committed
feature: each test starts with a unique seed. --randomly-use-same-seed-per-test for old behavior
1 parent 982506a commit 5175cc6

File tree

4 files changed

+67
-11
lines changed

4 files changed

+67
-11
lines changed

CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
Changelog
33
=========
44

5+
3.17.0
6+
-------------------
7+
8+
* Change default seed to be different per test. Add the option ``--randomly-use-same-seed-per-test`` to enable the old behavior.
9+
10+
Resolves `Issue #600 <https://github.com/pytest-dev/pytest-randomly/issues/600>`__
11+
12+
513
3.16.0 (2024-10-25)
614
-------------------
715

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,9 @@ You can disable behaviours you don't like with the following flags:
155155
* ``--randomly-dont-reset-seed`` - turn off the reset of ``random.seed()`` at
156156
the start of every test
157157
* ``--randomly-dont-reorganize`` - turn off the shuffling of the order of tests
158+
* ``--randomly-dont-seed-per-test`` - turn off each test having a unique seed.
159+
Each test will be seeded with the same seed.
160+
158161

159162
The plugin appears to Pytest with the name 'randomly'. To disable it
160163
altogether, you can use the ``-p`` argument, for example:

src/pytest_randomly/__init__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,13 @@ def pytest_addoption(parser: Parser) -> None:
105105
default=True,
106106
help="Stop pytest-randomly from randomly reorganizing the test order.",
107107
)
108+
group._addoption(
109+
"--randomly-use-same-seed-per-test",
110+
action="store_false",
111+
dest="same_seed_per_test",
112+
default=False,
113+
help="""Use a the same random seed for each test. Reproduces legacy behavior of pytest-randomly.""",
114+
)
108115

109116

110117
def pytest_configure(config: Config) -> None:
@@ -203,9 +210,17 @@ def pytest_runtest_setup(item: Item) -> None:
203210
_reseed(item.config, -1)
204211

205212

213+
def seed_from_string(string: str) -> int:
214+
return int(hashlib.md5(string.encode()).hexdigest(), 16)
215+
216+
206217
def pytest_runtest_call(item: Item) -> None:
207218
if item.config.getoption("randomly_reset_seed"):
208-
_reseed(item.config)
219+
if item.config.getoption("same_seed_per_test"):
220+
test_offset = 0
221+
else:
222+
test_offset = seed_from_string(item.nodeid) + 100
223+
_reseed(item.config, offset=test_offset)
209224

210225

211226
def pytest_runtest_teardown(item: Item) -> None:

tests/test_pytest_randomly.py

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,33 @@ def test_b():
7878
assert test_b.num == test_a.num
7979
"""
8080
)
81-
out = ourtester.runpytest("--randomly-dont-reorganize")
81+
out = ourtester.runpytest(
82+
"--randomly-dont-reorganize", "--randomly-use-same-seed-per-test"
83+
)
84+
out.assert_outcomes(passed=2, failed=0)
85+
86+
87+
def test_it_uses_different_random_seed_per_test(ourtester):
88+
"""
89+
Run a pair of tests that generate a number and assert they produce
90+
different numbers.
91+
"""
92+
ourtester.makepyfile(
93+
test_one="""
94+
import random
95+
96+
def test_a():
97+
test_a.num = random.random()
98+
if hasattr(test_b, 'num'):
99+
assert test_a.num != test_b.num
100+
101+
def test_b():
102+
test_b.num = random.random()
103+
if hasattr(test_a, 'num'):
104+
assert test_b.num != test_a.num
105+
"""
106+
)
107+
out = ourtester.runpytest()
82108
out.assert_outcomes(passed=2, failed=0)
83109

84110

@@ -601,7 +627,7 @@ def test_two(myfixture):
601627
assert random.getstate() == state_at_seed_two
602628
"""
603629
)
604-
args = ["--randomly-seed=2"]
630+
args = ["--randomly-seed=2", "--randomly-use-same-seed-per-test"]
605631

606632
out = ourtester.runpytest(*args)
607633
out.assert_outcomes(passed=2)
@@ -633,7 +659,7 @@ def test_b():
633659
"""
634660
)
635661

636-
out = ourtester.runpytest("--randomly-seed=1")
662+
out = ourtester.runpytest("--randomly-seed=1", "--randomly-use-same-seed-per-test")
637663
out.assert_outcomes(passed=2)
638664

639665

@@ -645,10 +671,10 @@ def test_faker(ourtester):
645671
fake = Faker()
646672
647673
def test_one():
648-
assert fake.name() == 'Ryan Gallagher'
674+
assert fake.name() == 'Justin Richard'
649675
650676
def test_two():
651-
assert fake.name() == 'Ryan Gallagher'
677+
assert fake.name() == 'Tiffany Williams'
652678
"""
653679
)
654680

@@ -692,7 +718,7 @@ def test_b():
692718
"""
693719
)
694720

695-
out = ourtester.runpytest("--randomly-seed=1")
721+
out = ourtester.runpytest("--randomly-seed=1", "--randomly-use-same-seed-per-test")
696722
out.assert_outcomes(passed=2)
697723

698724

@@ -702,10 +728,10 @@ def test_numpy(ourtester):
702728
import numpy as np
703729
704730
def test_one():
705-
assert np.random.rand() == 0.417022004702574
731+
assert np.random.rand() == 0.46479378116435255
706732
707733
def test_two():
708-
assert np.random.rand() == 0.417022004702574
734+
assert np.random.rand() == 0.6413112443155088
709735
"""
710736
)
711737

@@ -765,7 +791,9 @@ def fake_entry_points(*, group):
765791
entry_points.append(_FakeEntryPoint("test_seeder", reseed))
766792

767793
# Need to run in-process so that monkeypatching works
768-
pytester.runpytest_inprocess("--randomly-seed=1")
794+
pytester.runpytest_inprocess(
795+
"--randomly-seed=1", "--randomly-use-same-seed-per-test"
796+
)
769797
assert reseed.mock_calls == [
770798
mock.call(1),
771799
mock.call(1),
@@ -775,7 +803,9 @@ def fake_entry_points(*, group):
775803
]
776804

777805
reseed.mock_calls[:] = []
778-
pytester.runpytest_inprocess("--randomly-seed=424242")
806+
pytester.runpytest_inprocess(
807+
"--randomly-seed=424242", "--randomly-use-same-seed-per-test"
808+
)
779809
assert reseed.mock_calls == [
780810
mock.call(424242),
781811
mock.call(424242),

0 commit comments

Comments
 (0)