unittest style tests are allowed to use pytest fixtures through @pytest.mark.usefixtures().
However, if the fixture is paramterized, it crashes and burns and gives a bizarre message of:
E Failed: The requested fixture has no parameter defined for the current test.
That wouldn't be so terribly bad, if it wasn't for the other 96 lines of error message that come with it.
[x] pip list of the virtual environment you are using
pip (9.0.1)
py (1.4.34)
pytest (3.1.2)
setuptools (36.0.1)
wheel (0.29.0)
[x] pytest and operating system versions
platform linux -- Python 3.6.1, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
pytest 3.1.2, on Ubuntu Linux running on Windows 10.
test_one() will pass, test_two() will not only Error, it spews lots of rubbish to confuse the user.
import pytest
import unittest
@pytest.fixture()
def one():
return 42
@pytest.mark.usefixtures('one')
class TestSomething(unittest.TestCase):
def test_one(self):
pass
@pytest.fixture(params=[1,2])
def two(request):
return request.param
@pytest.mark.usefixtures('two')
class TestSomethingElse(unittest.TestCase):
def test_two(self):
pass
output
(unit_venv) okken@RSA22473:~/projects/unit/fail$ pytest test_something.py
================================== test session starts ==================================
platform linux -- Python 3.6.1, pytest-3.1.2, py-1.4.34, pluggy-0.4.0
rootdir: /home/okken/projects/unit/fail, inifile: pytest.ini
collected 2 items
test_something.py .E
======================================== ERRORS =========================================
_____________________ ERROR at setup of TestSomethingElse.test_two ______________________
self = <FixtureRequest for <TestCaseFunction 'test_two'>>
fixturedef = <FixtureDef name='two' scope='function' baseid='test_something.py' >
def _getfixturevalue(self, fixturedef):
# prepare a subrequest object before calling fixture function
# (latter managed by fixturedef)
argname = fixturedef.argname
funcitem = self._pyfuncitem
scope = fixturedef.scope
try:
> param = funcitem.callspec.getparam(argname)
E AttributeError: 'TestCaseFunction' object has no attribute 'callspec'
../unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:472: AttributeError
During handling of the above exception, another exception occurred:
self = <CallInfo when='setup' exception: The requested fixture has no parameter defined for the current test.
Requested fixt...mething.py:14
Requested here:
/home/okken/projects/unit/unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:382>
func = <function call_runtest_hook.<locals>.<lambda> at 0x7f7689467f28>, when = 'setup'
def __init__(self, func, when):
#: context of invocation: one of "setup", "call",
#: "teardown", "memocollect"
self.when = when
self.start = time()
try:
> self.result = func()
../unit_venv/lib/python3.6/site-packages/_pytest/runner.py:157:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../unit_venv/lib/python3.6/site-packages/_pytest/runner.py:145: in <lambda>
return CallInfo(lambda: ihook(item=item, **kwds), when=when)
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:745: in __call__
return self._hookexec(self, self._nonwrappers + self._wrappers, kwargs)
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:339: in _hookexec
return self._inner_hookexec(hook, methods, kwargs)
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:334: in <lambda>
_MultiCall(methods, kwargs, hook.spec_opts).execute()
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:613: in execute
return _wrapped_call(hook_impl.function(*args), self.execute)
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:254: in _wrapped_call
return call_outcome.get_result()
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:279: in get_result
raise ex[1].with_traceback(ex[2])
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:265: in __init__
self.result = func()
../unit_venv/lib/python3.6/site-packages/_pytest/vendored_packages/pluggy.py:614: in execute
res = hook_impl.function(*args)
../unit_venv/lib/python3.6/site-packages/_pytest/runner.py:94: in pytest_runtest_setup
item.session._setupstate.prepare(item)
../unit_venv/lib/python3.6/site-packages/_pytest/runner.py:449: in prepare
col.setup()
../unit_venv/lib/python3.6/site-packages/_pytest/unittest.py:79: in setup
self._request._fillfixtures()
../unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:382: in _fillfixtures
item.funcargs[argname] = self.getfixturevalue(argname)
../unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:424: in getfixturevalue
return self._get_active_fixturedef(argname).cached_result[0]
../unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:449: in _get_active_fixturedef
result = self._getfixturevalue(fixturedef)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <FixtureRequest for <TestCaseFunction 'test_two'>>
fixturedef = <FixtureDef name='two' scope='function' baseid='test_something.py' >
def _getfixturevalue(self, fixturedef):
# prepare a subrequest object before calling fixture function
# (latter managed by 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 'two' defined in:
E test_something.py:14
E
E Requested here:
E /home/okken/projects/unit/unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:382
../unit_venv/lib/python3.6/site-packages/_pytest/fixtures.py:494: Failed
=========================== 1 passed, 1 error in 0.58 seconds ===========================
Thanks @okken!
Is there any way to get around this and use a parameterized pytest fixture with a unittest test class?
@codeguru42 yes, you can inject fixtures using this technique. If you only need parametrized fixtures it might be enough.
@nicoddemus I am already using the autouse flag. The only other difference between the example in that link and what I am doing is that my fixture is a global function rather than a member of the TestCase subclass. Even when I put my fixture inside the class, I get the same "Failed: The requested fixture has no parameter defined for the current test." error.
I have posted a question on StackOverflow. If you would like me to post more details here or in a new issue instead, I will be happy to do so.
I rewrote the entire module in pytest and removed all references to unittest. This seems like the best solution for my particular situation. Hopefully I will be able to refactor the entire test suite to use pure pytest.
@codeguru42 yeah apparently the autouse trick does not work with parametrized fixtures. 馃槥
I rewrote the entire module in pytest and removed all references to unittest.
A quick note: if you need that parametrized fixture for a few tests, you might get away with moving those test methods into pytest-style test methods:
import unittest
import pytest
class Foo(unittest.TestCase):
def setUp(self):
print('unittest setUp()')
def test(self):
print('normal unittest')
class Test: # pytest-style
@pytest.fixture(autouse=True, params=['foo', 'bar'])
def foo(self, request):
print('fixture')
print(request.param)
def test(self, foo):
pass
Since autouse doesn't work with unittest and @parameterized, should this issue be considered a bug? (That would suggest this issue should be renamed as well).
I'm searching for a way to do parameterized tests in unittest class-based tests, and I can't see any supported way of doing this -- this is a significant issue for me, since in general Django tests must still use a TestCase subclass (for DB caching reasons discussed in https://github.com/pytest-dev/pytest-django/issues/514).
If there's a cunning way to get round this, I'd love to know it.
Since autouse doesn't work with unittest and @parameterized, should this issue be considered a bug?
You mean that autouse fixtures cannot be parametrized in unittest? I think this warrants investigation if it is possible to implement it, but I believe it is a separate issue than the one here.
@paultiplady would you please open a separate issue? Thanks!
Most helpful comment
Since
autousedoesn't work with unittest and@parameterized, should this issue be considered a bug? (That would suggest this issue should be renamed as well).I'm searching for a way to do parameterized tests in
unittestclass-based tests, and I can't see any supported way of doing this -- this is a significant issue for me, since in general Django tests must still use aTestCasesubclass (for DB caching reasons discussed in https://github.com/pytest-dev/pytest-django/issues/514).If there's a cunning way to get round this, I'd love to know it.