使用平面图时,在假设中获取“ LazyStrategy”对象而不是整数

问题描述

使用python测试框架hypothesis,我想实现一个相当复杂的测试策略组合:1.我想对由唯一字符集组成的创建字符串s进行测试。 2.我想通过函数func(s: str,n: int) -> Tuple[str,int]运行每个示例,该函数以字符串s和整数n作为参数。在这里,我也想通过假设填充整数,但是n的最大值应为len(s),即s的长度。我尝试使用flatmap,但对它的理解还不足以使其正常工作。这是我尝试过的最小示例:

from typing import Tuple

from hypothesis import given
from hypothesis.strategies import text,integers


def func(s: str,int]:
    for i in range(n):
        pass  # I do something here on s,which is not relevant to the question

    return (s,n)

# 1. Create the strategy for unique character strings:
unique_char_str = text().map(lambda s: "".join(set(s)))

#2. Create the complex strategy with flatmap:
confined_tuple_str_int = unique_char_str.flatmap(
    lambda s: func(s,integers(min_value=0,max_value=len(s)))
)

当我尝试使用这种新策略时,


@given(tup=confined_tuple_str_int)
def test_foo(tup):
    pass

我得到了失败的测试,声称

test_foo-TypeError:“ LazyStrategy”对象无法解释为整数

for i in range(n):的{​​{1}}行中,func不是整数,而是n对象。

这告诉我,我对LazyStrategy的工作方式有一些误解,但我无法自行解决

我该怎么做才能正确定义我的测试策略?

解决方法

使用flatmap时,您无法组合两种依赖策略-可以使用composite装饰器来完成:

@composite
def confined_tuple_str_int(draw,elements=text()):
    s = draw(lists(characters(),unique=True).map("".join))
    i = draw(integers(min_value=0,max_value=len(s)))
    return func(s,i)


@given(confined_tuple_str_int())
def test_foo(tup):
    print(tup)

通过draw参数,您可以获取策略的绘制值(例如,示例)-在这种情况下为唯一字符串-并使用它来创建依赖于该值的策略-在这种情况下为整数策略取决于字符串长度。在还从该策略中提取了一个示例之后,复合装饰器将根据这些示例值创建一个新策略,并将其返回。

免责声明:我是hypothesis的新手,所以我的术语可能有点过头。

编辑:已更新,以确保保留示例顺序,如Zac Hatfield-Dodds在评论中所建议。