Skip to content

Better error message needed for parametrized fixtures with unittest #2535

@okken

Description

@okken
  • Include a detailed description of the bug or suggestion

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.

  • 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)

  • 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.

  • Minimal example if possible

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 ===========================

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: parametrizerelated to @pytest.mark.parametrizetopic: reportingrelated to terminal output and user-facing messages and errors

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions