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

如何利用Hypothesis测试函数对NaN等越界值的断言行为,同时保障合法值的测试覆盖

如何利用Hypothesis测试函数对NaN等越界值的断言行为,同时保障合法值的测试覆盖

刚好我在项目里也经常碰到类似的需求,既要验证函数对合法输入的正常处理,又要确保非法输入能触发预期的断言,还不能让这两部分测试互相拖后腿。Hypothesis其实有很顺手的方案来解决这个问题,核心思路就是拆分测试用例,针对性生成测试样本,这样两边的覆盖都能保障。

先给你拆解下具体的做法:

第一步:单独测试合法输入,优化样本生成效率

原来的测试里用assume(not math.isnan(value))来过滤NaN,其实有点浪费Hypothesis的采样资源——毕竟生成的NaN样本都会被直接跳过,反而挤占了合法样本的测试机会。

我们可以直接用Hypothesis的策略参数,精准生成符合要求的合法输入,这样不用过滤,测试效率和覆盖度都会更高:

import math
from hypothesis import given, strategies as st

def inc(value: float) -> float:
    assert not math.isnan(value)
    return value + 1

# 专门测试合法输入的正常行为:允许无穷大,排除NaN
@given(st.floats(allow_nan=False, allow_infinity=True))
def test_inc_valid_inputs(value: float):
    if value in (math.inf, -math.inf):
        assert inc(value) == value
    else:
        assert inc(value) > value

这样Hypothesis会把所有采样资源都用在合法的浮点数上,不管是普通有限值还是正负无穷,都能被充分测试,完全不用担心覆盖打折扣。

第二步:单独测试非法输入,验证断言触发逻辑

对于NaN这种越界值,我们可以专门写一个测试用例,针对性生成这类非法样本,然后验证它们确实会触发AssertionError:

import pytest
from hypothesis import given, strategies as st

# 专门测试NaN输入触发断言
@given(st.floats(allow_nan=True, allow_infinity=False))
def test_inc_invalid_nan_raises_assertion(value: float):
    # 这里生成的样本都是NaN,直接验证调用函数时会抛出断言错误
    with pytest.raises(AssertionError):
        inc(value)

这个测试的目标非常明确,Hypothesis会集中生成NaN样本,确保我们的断言逻辑确实生效,不会出现“漏测”或者“误测”的情况。

为什么这种拆分方式更优?

  • 职责清晰:每个测试只干一件事,后期维护起来也方便,一眼就能看懂每个测试的目标
  • 覆盖充分:合法输入的测试不用再浪费采样机会在NaN上,Hypothesis可以把更多精力放在合法值的边缘场景(比如接近浮点数上下限的数值),保障覆盖质量
  • 精准验证:非法输入的测试专门针对NaN生成样本,不会出现“漏测”或者“误测”的情况

如果你实在想把两种逻辑放在同一个测试里(虽然我不太推荐,会让测试逻辑变复杂),也可以用st.one_of把合法和非法策略组合起来,然后在测试里分支处理,但这样Hypothesis会把采样资源分配给两种样本,反而可能降低合法值的测试密度,所以还是拆分的方案更稳妥。

备注:内容来源于stack exchange,提问作者Carl Patenaude Poulin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 18:17:59