关于pytest-randomly每次测试生成相同随机结果的问题咨询
我正尝试正确使用pytest-randomly工具(3.15.0版本),但遇到了每次测试都会生成相同随机数集合的问题。仅安装了该工具并正常运行测试,示例代码如下:
import random def generate_random_numbers(size): return [random.randint(1, 100) for _ in range(size)] def test_random_numbers_size_1(): numbers = generate_random_numbers(10) print(f"test_random_numbers_size 1.1: Generated numbers = {numbers}") numbers = generate_random_numbers(10) print(f"test_random_numbers_size 1.2: Generated numbers = {numbers}") assert len(numbers) == 10 def test_random_numbers_size_2(): numbers = generate_random_numbers(10) print(f"test_random_numbers_size 2.1: Generated numbers = {numbers}") numbers = generate_random_numbers(10) print(f"test_random_numbers_size 2.2: Generated numbers = {numbers}") assert len(numbers) == 10
运行结果:
... Using --randomly-seed=2523483435 test_example.py::test_random_numbers_size_2 PASSED [ 50%] test_random_numbers_size 2.1: Generated numbers = [26, 52, 25, 95, 2, 69, 11, 94, 74, 48] test_random_numbers_size 2.2: Generated numbers = [72, 41, 6, 27, 60, 28, 54, 48, 100, 76] test_example.py::test_random_numbers_size_1 PASSED [100%] test_random_numbers_size 1.1: Generated numbers = [26, 52, 25, 95, 2, 69, 11, 94, 74, 48] test_random_numbers_size 1.2: Generated numbers = [72, 41, 6, 27, 60, 28, 54, 48, 100, 76]
如您所见,每个测试方法生成的随机数完全重复。这不应该是不同的吗?是否可以为每个测试方法修改pytest-randomly的seed?我尝试过使用fixtures,但没有效果。
官方文档说明:
- 在每个测试用例和测试开始时将全局random.seed()重置为固定值——默认值为测试运行开始时的time.time(),但您可以传入--randomly-seed参数来复现由随机性导致的失败。
这是pytest-randomly的默认行为:它会在每个测试开始时把random模块的seed重置为同一个全局种子值(也就是运行时的--randomly-seed),目的是让测试可复现——只要种子相同,每次测试的随机序列就一致。
如果想要每个测试用例使用不同的随机序列,有以下几种实用方式:
1. 手动为每个测试生成独立seed(推荐,兼顾随机性和可复现性)
利用pytest-randomly提供的randomly_seed fixture,结合测试的唯一标识生成专属seed,手动重置random模块:
import random import pytest def generate_random_numbers(size): return [random.randint(1, 100) for _ in range(size)] @pytest.fixture(autouse=True) def unique_test_seed(randomly_seed, request): # 用全局seed + 测试节点ID生成唯一seed test_seed = hash((randomly_seed, request.node.nodeid)) % 2**32 random.seed(test_seed) def test_random_numbers_size_1(): numbers = generate_random_numbers(10) print(f"test_random_numbers_size 1.1: Generated numbers = {numbers}") numbers = generate_random_numbers(10) print(f"test_random_numbers_size 1.2: Generated numbers = {numbers}") assert len(numbers) == 10 def test_random_numbers_size_2(): numbers = generate_random_numbers(10) print(f"test_random_numbers_size 2.1: Generated numbers = {numbers}") numbers = generate_random_numbers(10) print(f"test_random_numbers_size 2.2: Generated numbers = {numbers}") assert len(numbers) == 10
这个方法的好处是:只要全局--randomly-seed不变,每个测试的专属seed也不变,测试结果依然可复现;同时不同测试的随机序列完全不同。
2. 禁用测试前的seed重置(不推荐,丢失可复现性)
在pytest.ini或pyproject.toml中添加配置,关闭测试级别的seed重置:
# pytest.ini [pytest] randomly_reset_seed_per_test = false
这样random模块的状态会在测试间延续,每个测试会得到不同的随机序列,但代价是测试结果无法通过固定seed复现。
3. 排除特定模块的seed干预
如果你只想让random模块在测试间不重置,其他模块(如numpy、django)保持默认行为,可以单独配置:
# pytest.ini [pytest] randomly_exclude = random
这样pytest-randomly不会干预random模块的seed状态,测试间会延续随机序列。
内容的提问来源于stack exchange,提问作者Duje

