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

Getting 'LazyStrategy' object instead of integer in hypothesis when using flatmap

使用 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, n: int) -> Tuple[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' object cannot be interpreted as an integer

在行for i in range(n):中,在func中,n不是一个整数,而是一个LazyStrategy对象。

这告诉我,我对 flatmap 的工作原理有一些误解,但我自己无法弄明白。

我需要做什么才能正确定义我的测试策略?

使用 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 参数允许您获取策略的绘制值(例如示例)——在本例中为唯一字符串——并使用它创建依赖于该值的策略——在本例中取决于字符串长度的整数策略。在还从该策略中提取示例后,复合装饰器从这些示例值和 returns 创建一个新策略。

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

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