You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python Hypothesis库中text()策略为何导致自定义策略重试?

Hypothesis composite策略调用次数异常问题

我用composite构建了一个内部调用text()策略的自定义策略,调试FailedHealthCheck.data_too_large错误时发现,调用text()会让自定义策略的执行次数比预期多一倍左右。

我复现了最小示例代码:

import hypothesis
from hypothesis import strategies as st

def trace(msg):
    # 用于追踪调用次数的辅助函数
    if not hasattr(trace, "counts"):
        trace.counts = {}
    trace.counts[msg] = trace.counts.get(msg, 0) + 1
    print(f"{msg}: {trace.counts[msg]}")

@st.composite
def my_custom_strategy(draw, n):
    """生成包含N个字符串的列表的策略"""
    trace("a")
    value = [draw(st.text(max_size=256)) for _ in range(n)]
    trace("b")
    return value

@hypothesis.given(my_custom_strategy(100))
def test_my_custom_strategy(value):
    assert len(value) == 100
    assert all(isinstance(v, str) for v in value)

if __name__ == "__main__":
    test_my_custom_strategy()

运行后发现trace("a")被调用206次,trace("b")仅被调用100次,多次运行数据一致。更严重的是,调用text()的次数越多,差距呈超线性增长:n=200时,trace("a")被调用305次;n=400时为984次;n≥500时,测试会暂停,仅完成11次迭代而非预期的100次。

原因解释

这是Hypothesis的收缩(shrinking)机制和**健康检查(health check)**共同作用的结果:

  • 收缩机制:当Hypothesis生成的测试用例触发失败(这里是data_too_large健康检查失败),它会尝试收缩用例,找到最小的触发失败的输入。收缩过程中会多次重新执行自定义策略,尝试减少字符串长度、调整生成内容,这就导致trace("a")被多次调用,但只有当策略成功生成符合要求的用例时才会走到trace("b")。
  • data_too_large健康检查:当生成的测试数据总大小超过阈值(默认1MB),Hypothesis会触发该检查失败。当n增大时,n个最大256字符的字符串总大小容易接近或超过阈值,Hypothesis会反复尝试生成更小的用例,导致策略调用次数暴增,甚至因多次尝试失败提前终止测试。
  • 超线性增长的原因:每次text()生成的字符串长度随机,n越大,总大小超阈值的概率非线性上升。Hypothesis在收缩和重试时,需要多次重新执行整个自定义策略来调整每个字符串的长度,导致调用次数增长速度远超n的增长速度。

解决建议

  • 降低text()的max_size,减少单条数据大小,避免触发data_too_large检查。
  • 若确认数据大小合理,可通过@hypothesis.settings(suppress_health_check=[hypothesis.HealthCheck.data_too_large])关闭该健康检查(不推荐随意关闭)。
  • 改用st.lists(st.text(max_size=256), min_size=n, max_size=n)代替手动循环draw,Hypothesis对内置lists策略有优化,能减少不必要的重试和收缩次数。

内容的提问来源于stack exchange,提问作者levand

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 03:52:52