我正在测试我写的一个数学函数。我想提供数据,它从一个不同的装置数。问题是所有的夹具都接受自己的不同夹具参数。
我运行的测试总是一样的(
test_myfunc
在本例中),以及我要插入其中的fixture都具有相同的兼容返回值(
clean_data
和
noisy_data
在代码中)。因此,我想将这两个fixture“链接”在一起,以便其中一个为测试提供输入。
下面是设置的样子:
import numpy as np
import pytest
from scipy import stats
def myfunc(x, y):
return True
_noises = {
'normal': lambda scale, n: np.random.normal(scale=scale, size=n),
'uniform': lambda scale, n: np.random.uniform(-scale, scale, size=n),
'triangle': lambda scale, n: np.random.triangular(-scale, 0, scale, size=n),
}
@pytest.fixture(params=[10**x for x in range(1, 4)])
def x_data(request):
""" Run the test on a few different densities """
return np.linspace(-10, 10, request.param)
@pytest.fixture(params=[0, 1, 0xABCD, 0x1234])
def random_seed(request):
""" Run the test for a bunch of datasets, but reporoducibly """
np.random.seed(request.param)
@pytest.fixture(params=np.arange(0.5, 5.5, 0.5))
def shape(request):
""" Run the test with a bunch of different curve shapes """
return request.param
@pytest.fixture()
def clean_data(x_data, shape):
""" Get a datset with no noise """
return shape, stats.gamma.pdf(x_data, shape)
@pytest.fixture(params=["triangle", "uniform", "normal"])
def noisy_data(request, clean_data, random_seed):
shape, base = clean_data
noise = _noises[request.param](10, base.shape)
return shape, base + noise
def test_myfunc(x_data, data):
shape, y_data = data
assert myfunc(x_data, y_data)
自从
清除\u数据
和
噪声数据
fixtures返回相同类型的结果,我希望能够在我的测试中使用它们,一个接一个。如何使用多个接受参数的fixture运行单个测试?
如果可能,我希望避免生成测试。我熟悉间接参数化测试的想法,例如
Running the same test on two different fixtures
@pytest.fixture()
def data(request):
""" Get the appropriate datset based on the request """
return request.getfuncargvalue(request.param)
@pytest.mark.parametrize('data', ['clean_data', 'noisy_data'], indirect=True)
def test_myfunc(x_data, data):
shape, y_data = data
assert myfunc(x_data, y_data)
当我用
pytest -v pytest-parametrized.py
我得到了一系列错误,这些错误似乎都指向这样一个事实:间接夹具需要参数,但没有提供参数:
_________________ ERROR at setup of test_myfunc[10-clean_data] _________________
self = <_pytest.python.CallSpec2 object at 0x7f8a4ff06518>, name = 'shape'
def getparam(self, name):
try:
> return self.params[name]
E KeyError: 'shape'
/usr/lib/python3.6/site-packages/_pytest/python.py:684: KeyError
During handling of the above exception, another exception occurred:
self = <SubRequest 'clean_data' for <Function 'test_myfunc[10-clean_data]'>>
fixturedef = <FixtureDef name='shape' scope='function' baseid='pytest-parametrized.py' >
def _compute_fixture_value(self, fixturedef):
"""
Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will
force the FixtureDef object to throw away any previous results and compute a new fixture value, which
will be stored into the FixtureDef object itself.
:param FixtureDef fixturedef:
"""
argname = fixturedef.argname
funcitem = self._pyfuncitem
scope = fixturedef.scope
try:
> param = funcitem.callspec.getparam(argname)
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:484:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_pytest.python.CallSpec2 object at 0x7f8a4ff06518>, name = 'shape'
def getparam(self, name):
try:
return self.params[name]
except KeyError:
if self._globalparam is NOTSET:
> raise ValueError(name)
E ValueError: shape
/usr/lib/python3.6/site-packages/_pytest/python.py:687: ValueError
During handling of the above exception, another exception occurred:
request = <SubRequest 'data' for <Function 'test_myfunc[10-clean_data]'>>
@pytest.fixture()
def data(request):
""" Get the appropriate datset based on the request """
> return request.getfuncargvalue(request.param)
pytest-parametrized.py:55:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:439: in getfuncargvalue
return self.getfixturevalue(argname)
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:430: in getfixturevalue
return self._get_active_fixturedef(argname).cached_result[0]
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:455: in _get_active_fixturedef
self._compute_fixture_value(fixturedef)
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:526: in _compute_fixture_value
fixturedef.execute(request=subrequest)
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:778: in execute
fixturedef = request._get_active_fixturedef(argname)
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:455: in _get_active_fixturedef
self._compute_fixture_value(fixturedef)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <SubRequest 'clean_data' for <Function 'test_myfunc[10-clean_data]'>>
fixturedef = <FixtureDef name='shape' scope='function' baseid='pytest-parametrized.py' >
def _compute_fixture_value(self, fixturedef):
"""
Creates a SubRequest based on "self" and calls the execute method of the given fixturedef object. This will
force the FixtureDef object to throw away any previous results and compute a new fixture value, which
will be stored into the FixtureDef object itself.
:param FixtureDef fixturedef:
"""
argname = fixturedef.argname
funcitem = self._pyfuncitem
scope = fixturedef.scope
try:
param = funcitem.callspec.getparam(argname)
except (AttributeError, ValueError):
param = NOTSET
param_index = 0
if fixturedef.params is not None:
frame = inspect.stack()[3]
frameinfo = inspect.getframeinfo(frame[0])
source_path = frameinfo.filename
source_lineno = frameinfo.lineno
source_path = py.path.local(source_path)
if source_path.relto(funcitem.config.rootdir):
source_path = source_path.relto(funcitem.config.rootdir)
msg = (
"The requested fixture has no parameter defined for the "
"current test.\n\nRequested fixture '{0}' defined in:\n{1}"
"\n\nRequested here:\n{2}:{3}".format(
fixturedef.argname,
getlocation(fixturedef.func, funcitem.config.rootdir),
source_path,
source_lineno,
)
)
> fail(msg)
E Failed: The requested fixture has no parameter defined for the current test.
E
E Requested fixture 'shape' defined in:
E pytest-parametrized.py:27
E
E Requested here:
E /usr/lib/python3.6/site-packages/_pytest/fixtures.py:526
/usr/lib/python3.6/site-packages/_pytest/fixtures.py:506: Failed