获取 .片状:数据生成不一致!在 Python 假设中

Getting .Flaky: Inconsistent data generation! in Python hypothesis

提问人:Prabhleen Singh 提问时间:7/4/2023 最后编辑:Zac Hatfield-DoddsPrabhleen Singh 更新时间:7/4/2023 访问量:35

问:

我的测试是使用 (API) 创建策略,但 API 不允许重复的规则名称。 所以假设重试 API 时必然会给出不允许重复的名称。

如果在我的代码中添加逻辑以首先删除策略,如果生成了相同的规则名称,那么我点击

hypothesis.errors.Flaky: Inconsistent data generation! Data generation behaved differently between different runs. Is your data generation depending on external state?
import string
from hypothesis import assume
import pytest
import unittest
from hypothesis import strategies as st, reject
from hypothesis.stateful import RuleBasedStateMachine, precondition, rule


used_names = set()


@st.composite
def unique_name_strategy(draw):
    name_strategy = st.text(min_size=5, max_size=31, alphabet=string.ascii_letters + string.digits)
    while True:
        name = draw(name_strategy)
        if name not in used_names:
            used_names.add(name)
            return name


class TestsEdlp(RuleBasedStateMachine):
    def __init__(self) -> None:
        super().__init__()

    rule_names = []
    tries = 0


    def rule_creation(self, rule_name):
        print("in rule creation")

        if rule_name in self.rule_names:
            self.rule_names.remove(rule_name)

        if rule_name:
            self.rule_names.append(rule_name)
            self.tries += 1
            return True
        else:
            return False


    @precondition(lambda self: self.tries < 10)
    @rule(rule_name=unique_name_strategy())
    def create_dlp_rule(self, rule_name):

        print(f"in function create rule {rule_name} tries: {self.tries}")
        is_success = self.rule_creation(rule_name=rule_name)
        assert is_success

TestsEdlp: unittest.TestCase = TestsEdlp.TestCase
自动化 pytest 假设 - 测试 python 假设

评论


答:

0赞 Zac Hatfield-Dodds 7/4/2023 #1

问题在于,唯一名称的策略不允许 Hypothesis 在测试函数的两次不同运行中生成相同的名称,这必须被允许 - 否则,我们无法尝试变体或发现最小的失败示例(以及其他问题)。

这可能还需要做一些工作来重置每个输入假设尝试的 API 状态。(正如您后来对此问题的评论所暗示的那样)

更好的唯一名称策略是:

@st.composite
def unique_name_strategy(draw, name_strategy=st.text(string.ascii_letters + string.digits, min_size=5, max_size=31)):
    used_names = draw(st.shared(st.builds(set), key="used names"))
    name = draw(name_strategy.filter(lambda x: x not in used_names)
    used_names.add(name)
    return name

该策略只会为每个输入生成一个集合,因此我们获得了恰到好处的持久性。st.shared()