NOhs
NOhs

Reputation: 2830

How to make commandline arguments available in decorators using pytest?

Context

What I am trying to achieve is to have a decorator which, depending on a command line argument, will change how the test is run:

import pytest
from functools import wraps


def magic():

    # obtain extra_bit
    extra_bit = ...

    def wrapper(f):
        if extra_bit:
            @wraps(f)
            def test_func(*args, **kwars):
                f(*args, **kwars)
        else:
            @wraps(f)
            def test_func(*args, **kwargs):
                assert 0

        return test_func

    return wrapper

Calling this decorator as:

@magic(4)
def test_this():
    assert 0

The calling interface is important, as the commandline argument should not appear here (as the user of the decorator never does anything with it).

Paraphrased from the pytest documentation

(https://docs.pytest.org/en/latest/example/simple.html)

It is quite easy to make commandline arguments available as fixtures to test functions in pytest:

import pytest

def pytest_addoption(parser):
    parser.addoption('--extra_bit', action='store_true')

@pytest.fixture
def extra_bit(request):
    return request.config.getoption('--extra_bit')

and then using them in a test

def test_this(extra_bit):
    assert extra_bit

However, these fixtures only work when used in the definition of a test_ function, and not for arbitrary functions in your test module.

Question

How can I obtain command line arguments from pytest if not via test_ function arguments/fixtures?

Upvotes: 0

Views: 538

Answers (1)

NOhs
NOhs

Reputation: 2830

Answer in short

Using pytest_configure one can make the option available in a conftest.py file.

conftest.py

import pytest

_EXTRA_BIT = False

def extra_bit():
    return _EXTRA_BIT

def pytest_addoption(parser):
    parser.addoption("--extra_bit", action="store_true")

def pytest_configure(config):
    global _EXTRA_BIT
    _EXTRA_BIT = config.getoption("--extra_bit")

testplugin.py

from conftest import extra_bit
from functools import wraps


def magic():

    # obtain extra_bit
    extra_bit = extra_bit()

    def wrapper(f):
        if extra_bit:
            @wraps(f)
            def test_func(*args, **kwars):
                f(*args, **kwars)
        else:
            @wraps(f)
            def test_func(*args, **kwargs):
                assert 0

        return test_func

    return wrapper

EDIT: The old answer below uses the deprecated pytest.config module.

Answer in short

So it turns out that pytest does offer that functionality via the pytest.config module. The documentation for this is here: https://docs.pytest.org/en/latest/reference.html#_pytest.config.Config. The function one can use is the getoption function.

Adapted example

import pytest
from functools import wraps


def magic():

    # obtain extra_bit
    extra_bit = pytest.config.getoption('--extra_bit')

    def wrapper(f):
        if extra_bit:
            @wraps(f)
            def test_func(*args, **kwars):
                f(*args, **kwars)
        else:
            @wraps(f)
            def test_func(*args, **kwargs):
                assert 0

        return test_func

    return wrapper

Upvotes: 1

Related Questions