3

I'm getting following error by passing my fixture defined in conftest.py in @pytest.mark.parametrize:

pytest --alist="0220,0221" test_1.py -v -s
NameError: name 'alist' is not defined

conftest.py:

def pytest_addoption(parser):
    parser.addoption("--alist", action="store")

@pytest.fixture
def alist(request):
    return request.config.getoption("--alist").split(",")

test_1.py:

@pytest.mark.parametrize("channel", alist, scope="class")
class TestRaIntegrationReplay:

    def test_ra_start_time(self, channel):
        print(channel)

If I am passing alist to the test as fixture like:

    def test_ra_start_time(self, alist):
        for channel in alist:
            print(channel)

It works well, but it does not work with passing to @pytest.mark.parametrize

Valery Fludkov
  • 135
  • 1
  • 3
  • 15
  • 1
    I have answered a [similar question](https://stackoverflow.com/a/63622139/12480730) some time ago, should work for your case too, e.g. do the parametrization in `pytest_generate_tests`, as you cannot pass a fixture to `mark.parametrize` directly. – MrBean Bremen Dec 14 '20 at 15:58
  • @MrBeanBremen thanks, I managed to apply your first solution with modifying "pytest_generate_tests" hook in conftest.py and it worked, but I have another question now: is there a way to apply alist fixture to all tests in the class to avoid passing "alist" fixture to every test? Or there is a way to modify pytest_generate_tests to apply hook in case of fixture alist applied to the class? – Valery Fludkov Dec 14 '20 at 16:42
  • 1
    I'm not sure I understand: you don't want to use the fixture genererally, or you just want to use it where needed? The second case is already covered by the `if "alist" in metafunc.fixturenames` part. – MrBean Bremen Dec 14 '20 at 16:51
  • 1
    I'll put it in an answer to clarify with the risk of creating a duplicate... That will make it easier to discuss it. – MrBean Bremen Dec 14 '20 at 16:58

1 Answers1

3

As mentioned in the comment, you cannot directly pass a fixture to a mark.parametrize decorator, because the decorator is evaluated at load time.
You can do the parametrization at run time instead by implementing pytest_generate_tests:

import pytest

@pytest.hookimpl
def pytest_generate_tests(metafunc):
    if "alist" in metafunc.fixturenames:
        values = metafunc.config.option.alist
        if value is not None:
            metafunc.parametrize("alist", value.split(","))

def test_ra_start_time(alist):
    for channel in alist:
        print(channel)

def test_something_else():
    # will not be parametrized
    pass

The parametrization is done based on the presence of the alist parameter in the test function. For parametrization to work, this parameter is needed (otherwise you would get an error because of the missing argument).

MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46