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

如何在Python Hypothesis测试中结合@pytest.fixture与@given装饰器?

如何结合pytest fixture与Hypothesis的given参数化?

我正在使用pytest和Hypothesis做Python的基于属性测试。我想测试自定义Matrix类的构造函数是否正确分配行列数,希望两个独立测试函数共享同一个实例(用pytest.fixture实现),同时用hypothesis.given装饰器,通过hypothesis.strategies.integers生成的随机seed参数化测试。

尝试直接给fixture加@given装饰器时,出现fixture 'matrix' not found错误,请问能不能结合这两个特性?如果不能,有什么替代方案?

原可运行测试示例:

import numpy as np
from pytest import fixture

class Matrix:
    def __init__(self, nrows, ncols, seed=None):
        np.random.seed(seed)
        self.array = np.random.rand(nrows, ncols)

@fixture(scope='module')
def matrix():
    return Matrix(nrows=2, ncols=3)

def test_nrows(matrix):
    assert matrix.array.shape[0] == 2

def test_ncols(matrix):
    assert matrix.array.shape[1] == 3

错误尝试的代码:

from hypothesis import given, strategies

@given(seed=strategies.integers())
@fixture(scope='module')
def matrix(seed):
    return Matrix(nrows=2, ncols=3, seed=seed)

结论:不能直接给fixture叠加@given装饰器

@given是Hypothesis用来参数化测试函数的工具,而fixture是pytest的依赖注入机制,两者执行逻辑不兼容。直接叠加会导致pytest无法识别该fixture,因此出现找不到fixture的错误。

替代方案

方案1:给测试类加@given装饰器,共享实例

把需要共用同一个Matrix实例的测试函数放到一个测试类中,给类添加@given装饰器,这样整个类的测试都会使用同一组随机seed生成的实例:

import numpy as np
from hypothesis import given, strategies

class Matrix:
    def __init__(self, nrows, ncols, seed=None):
        np.random.seed(seed)
        self.array = np.random.rand(nrows, ncols)

@given(seed=strategies.integers())
class TestMatrix:
    def setup_method(self, method, seed):
        self.matrix = Matrix(nrows=2, ncols=3, seed=seed)
    
    def test_nrows(self):
        assert self.matrix.array.shape[0] == 2
    
    def test_ncols(self):
        assert self.matrix.array.shape[1] == 3

方案2:fixture中生成单次随机seed(仅单实例共享)

如果不需要多组seed测试,仅需单次随机seed的共享实例,可以在fixture内生成Hypothesis风格的随机seed:

import numpy as np
from pytest import fixture
from hypothesis import strategies
from hypothesis.internal.conjecture import engine

class Matrix:
    def __init__(self, nrows, ncols, seed=None):
        np.random.seed(seed)
        self.array = np.random.rand(nrows, ncols)

@fixture(scope='module')
def matrix():
    seed = engine.random_state().draw(strategies.integers())
    return Matrix(nrows=2, ncols=3, seed=seed)

def test_nrows(matrix):
    assert matrix.array.shape[0] == 2

def test_ncols(matrix):
    assert matrix.array.shape[1] == 3

该方案仅生成一组随机seed,无法像@given那样自动探索边界值。

方案3:结合pytest.mark.parametrize与Hypothesis策略

手动生成若干组seed参数,配合pytest的参数化fixture,实现多组seed下的实例共享:

import numpy as np
from pytest import fixture, mark
from hypothesis import strategies

class Matrix:
    def __init__(self, nrows, ncols, seed=None):
        np.random.seed(seed)
        self.array = np.random.rand(nrows, ncols)

# 手动生成5组随机seed
seeds = [strategies.integers().example() for _ in range(5)]

@fixture(scope='module', params=seeds)
def matrix(request):
    return Matrix(nrows=2, ncols=3, seed=request.param)

def test_nrows(matrix):
    assert matrix.array.shape[0] == 2

def test_ncols(matrix):
    assert matrix.array.shape[1] == 3

该方案支持多组seed测试,但seed数量需手动指定,无法自动进行Hypothesis的智能边界探索。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 14:49:53