0

我有一个这样的函数(它实际上是一个类,但考虑到 Python 的鸭子类型,这无关紧要):

def myfunc(a=None, b=None):
    <snip>

现在我想编写一个始终提供a但仅有时提供的假设测试b

我试过了

from hypothesis import given, strategies as strat

@given(a=strat.booleans())
@given(b=strat.integers(min_value=1) | strat.nothing())
def test_model_properties(self, **kwargs):
    myval = myfunc(**kwargs)
    <snip>

但似乎它strat.nothing()只是跳过了该测试运行(hypothesis.errors.FailedHealthCheck: It looks like your strategy is filtering out a lot of data.当我使用它作为唯一策略时b)。

我怎样才能有时只提供一个带有假设检验的论点?我是否需要编写两个测试,一个有b一个没有?

4

4 回答 4

2

您的方法肯定会失败,因为正如假设文档所暗示的那样

hypothesis.strategies.nothing()[source]

    This strategy never successfully draws a value and will always reject on an attempt to draw.

您不提供价值的尝试b总是会失败。

这个怎么样:

from hypothesis.strategies import tuples, integers, booleans, one_of
B = booleans()
I = integers(min_value=0, max_value=10)
one_of(tuples(B), tuples(B, I)).example()

经过一系列试验,它给了我输出,例如(True,)(False, 9)、和。(False, 4)(True, 5)(False,)

当然,您可以将其与*args而不是**kwargs.

于 2017-11-01T12:53:10.047 回答
1

jacq 的回答让我走上了正轨——关键词的选择需要有自己的策略。

用标准字典

std = {'a': strat.booleans()}

和可选字典

opt = {
    'b': strat.integers(),
    'c': strat.integers(),
}

然后我可以对所有可能的“可选参数组合”使用链表理解:

# chain.from_iterable may or may not be faster; it doesn't matter for me.
optional = [combo
            for n in range(len(opt.items()))
            for combo in itertools.combinations(opt.items(), n+1)]

b这会生成、c和的键值元组(b, c)

为了绘制一组值,我们需要获得其中一个选项,可以使用sampled_from(optional). 使用获得的元组,除了std字典中的策略外,我们还必须从其中的策略中提取。

strat.sampled_from(optional).flatmap(
    lambda x: strat.fixed_dictionaries(
        {**std, **dict(x)}
    )
)

这都可以包装在一个函数中,我们称之为valid_values()@given(valid_values())如果您指定*args**kwargs在包装函数的签名中,则不能使用。

结果,test_model_properties(self, **kwargs)变为test_model_properties(self, kwargs)(并且您可以使用@given(kwargs=valid_values())) - 通过调用字典kwargs,函数的其余部分保持不变。

注意:如果您希望没有可选参数的可能性,这将不包括空元组,但可以optional轻松地将其附加到列表中。或者,有range(n+1)而不是combinations(..., n+1),因此包括长度 0。

于 2017-11-14T11:58:49.737 回答
1

看起来你想要none()而不是nothing()

from hypothesis import given, strategies as strat

@given(a=strat.booleans(), b=strat.none() | strat.integers(min_value=1))
def test_model_properties(self, **kwargs):
    myval = myfunc(**kwargs)
    ...

这比生成字典以用作 **kwargs 更简单,而且效率也更高。策略的顺序b也很重要 -none()放在首位确保最小示例将a=False, b=None代替a=False, b=1.

另请注意,@given与单次使用相比,多次应用效率非常低,实际上自 3.34.0 版以来已弃用。

于 2018-02-01T02:58:50.960 回答
-1

怎么样:

def myfunc(a=None, b=None):
    if b is None:
        b=strat.nothing() 
        # Or whatever you would like b to be when you don't supply an argument
    else:
        <snip>

因此,您让b默认值(在本例中为None)触发内部的“if”条件myfunc(),将其设置为其他值。

于 2017-11-01T09:55:25.910 回答