Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a command line argument to a py.test fixture as a parameter

Tags:

python

pytest

Admittedly it is not the best way to do it to start with and more importantly the fixture parameters are resolved i.e. Options.get_option() is called before everything else. Recommendations and suggestions would be appreciated.

From config.py

class Options(object):
    option = None

    @classmethod
    def get_option(cls):
        return cls.option

From conftest.py

@pytest.yield_fixture(scope='session', autouse=True)
def session_setup():
    Options.option = pytest.config.getoption('--remote')

def pytest_addoption(parser):
    parser.addoption("--remote", action="store_true", default=False, help="Runs tests on a remote service.")




@pytest.yield_fixture(scope='function', params=Options.get_option())
def setup(request):
    if request.param is None:
        raise Exception("option is none")
like image 571
mehmetg Avatar asked Aug 05 '16 18:08

mehmetg


2 Answers

Don't use custom Options class but directly ask for option from config.

pytest_generate_tests may be used for parametrizing fixture-like argument for tests.

conftest.py

def pytest_addoption(parser):
    parser.addoption("--pg_tag", action="append", default=[],
                     help=("Postgres server versions. "
                           "May be used several times. "
                           "Available values: 9.3, 9.4, 9.5, all"))

def pytest_generate_tests(metafunc):
    if 'pg_tag' in metafunc.fixturenames:
        tags = set(metafunc.config.option.pg_tag)
        if not tags:
            tags = ['9.5']
        elif 'all' in tags:
            tags = ['9.3', '9.4', '9.5']
        else:
            tags = list(tags)
        metafunc.parametrize("pg_tag", tags, scope='session')

@pytest.yield_fixture(scope='session')
def pg_server(pg_tag):
    # pg_tag is parametrized parameter
    # the fixture is called 1-3 times depending on --pg_tag cmdline

Edit: Replaced old example with metafunc.parametrize usage.

like image 103
Andrew Svetlov Avatar answered Oct 08 '22 16:10

Andrew Svetlov


There is an example in the latest docs on how to do this. It's a little buried and honestly I glazed over it the first time reading through the documentation: https://docs.pytest.org/en/latest/parametrize.html#basic-pytest-generate-tests-example.

Basic pytest_generate_tests example

Sometimes you may want to implement your own parametrization scheme or implement some dynamism for determining the parameters or scope of a fixture. For this, you can use the pytest_generate_tests hook which is called when collecting a test function. Through the passed in metafunc object you can inspect the requesting test context and, most importantly, you can call metafunc.parametrize() to cause parametrization.

For example, let’s say we want to run a test taking string inputs which we want to set via a new pytest command line option. Let’s first write a simple test accepting a stringinput fixture function argument:

# content of test_strings.py

def test_valid_string(stringinput):
    assert stringinput.isalpha()

Now we add a conftest.py file containing the addition of a command line option and the parametrization of our test function:

# content of conftest.py

def pytest_addoption(parser):
    parser.addoption("--stringinput", action="append", default=[],
        help="list of stringinputs to pass to test functions")

def pytest_generate_tests(metafunc):
    if 'stringinput' in metafunc.fixturenames:
        metafunc.parametrize("stringinput",
                             metafunc.config.getoption('stringinput'))

If we now pass two stringinput values, our test will run twice:

$ pytest -q --stringinput="hello" --stringinput="world" test_strings.py`
..
2 passed in 0.12 seconds
like image 43
jasonrhaas Avatar answered Oct 08 '22 16:10

jasonrhaas