使用Hypothesis的st.uuids()生成唯一ID出现重复,求解决方法
我希望生成不重复的唯一ID,尝试使用st.uuids()策略。以下是我的测试代码:
class MyTest(unittest.TestCase): def setUp(self): self.ids = [] # 补充初始化逻辑,原代码可能遗漏 @hypothesis.seed(0) @hypothesis.settings(derandomize=True) @hypothesis.settings(use_coverage=False) # 修正原代码笔误:setting → settings @hypothesis.given(st.uuids()) def test(self, test_id): logging.info('test_id %s', test_id) logging.info('self.ids %s', self.ids) if test_id in self.ids: logging.info('SHOULD NOT BE HERE') else: logging.info('HAPPY') self.ids.append(test_id)
但测试中出现了1次重复,日志显示重复的test_id已存在于self.ids列表中。我怀疑@cacheable或@defines_strategy_with_reusable_values装饰器可能与此有关,请问有什么避免重复的技巧?
先给你理清楚核心原因:Hypothesis的st.uuids()本身是生成随机UUID的,但Hypothesis的属性测试机制会主动生成重复值来验证代码边界——这是它的核心功能之一,刻意用重复输入测试你的代码是否能处理这类场景。不过如果你的需求是强制生成完全不重复的UUID,这里有几个实用技巧:
1. 用unique()包装UUID策略
这是最直接的解决方案,Hypothesis提供了unique()方法确保策略生成的所有值在单次测试运行中完全唯一:
from hypothesis import strategies as st # 定义无重复的UUID策略 unique_uuid_strategy = st.uuids().unique()
然后在测试中替换原来的st.uuids():
@hypothesis.given(unique_uuid_strategy) def test(self, test_id): # 你的测试逻辑不变
这个方法会自动过滤重复值,确保每次传入的test_id都是全新的。
2. 调整测试配置避免确定性重复
你开启了derandomize=True,这个模式下Hypothesis会使用固定的伪随机序列生成值。虽然UUID重复概率极低,但如果测试运行次数足够多,伪随机序列的周期特性可能导致重复。如果不需要确定性测试,可以关闭该设置:
@hypothesis.settings(derandomize=False, use_coverage=False)
不过这只是降低重复概率,不如unique()彻底。
3. 规避缓存类装饰器的影响
你怀疑的两个装饰器确实可能导致重复:
@cacheable会缓存策略生成的值,后续调用可能直接返回缓存的旧值,绝对不能用在需要唯一值的策略上- 如果自定义策略用了
@defines_strategy_with_reusable_values,可以通过max_reuses=1限制重复次数,或者直接移除该装饰器,确保每次生成全新的UUID
4. 确保ID列表的正确初始化
别忘了检查self.ids的初始化方式!如果是在类级别定义的列表,多个测试用例会共享同一个列表,累积之前的ID自然会出现重复。一定要在setUp()方法里初始化:
class MyTest(unittest.TestCase): def setUp(self): self.ids = [] # 每个测试前重置列表
这是容易忽略的细节,但也是跨测试重复的常见原因。
额外说明
如果你的测试目的是验证“处理唯一ID的逻辑”,其实Hypothesis生成重复值是在帮你测试边界情况——比如代码是否能正确处理重复ID的异常场景。但如果需求是强制所有测试输入都是唯一的,上面的技巧就能完美解决问题。
内容的提问来源于stack exchange,提问作者curious_george

