How to pass arguments in pytest by command line

99,340

Solution 1

In your pytest test, don't use @pytest.mark.parametrize:

def test_print_name(name):
    print ("Displaying name: %s" % name)

In conftest.py:

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


def pytest_generate_tests(metafunc):
    # This is called for every test. Only get/set command line arguments
    # if the argument is specified in the list of test "fixturenames".
    option_value = metafunc.config.option.name
    if 'name' in metafunc.fixturenames and option_value is not None:
        metafunc.parametrize("name", [option_value])

Then you can run from the command line with a command line argument:

pytest -s tests/my_test_module.py --name abc

Solution 2

Use the pytest_addoption hook function in conftest.py to define a new option.
Then use pytestconfig fixture in a fixture of your own to grab the name.
You can also use pytestconfig from a test to avoid having to write your own fixture, but I think having the option have it's own name is a bit cleaner.

# conftest.py

def pytest_addoption(parser):
    parser.addoption("--name", action="store", default="default name")
# test_param.py 

import pytest

@pytest.fixture(scope="session")
def name(pytestconfig):
    return pytestconfig.getoption("name")

def test_print_name(name):
        print(f"\ncommand line param (name): {name}")

def test_print_name_2(pytestconfig):
    print(f"test_print_name_2(name): {pytestconfig.getoption('name')}")
# in action

$ pytest -q -s --name Brian test_param.py

test_print_name(name): Brian
.test_print_name_2(name): Brian
.

Solution 3

I stumbled here looking for how to pass an argument, but I wanted to avoid parameterizing the test. The accepted answer does perfectly well address the exact question of parameterizing a test from the command line, but I would like to offer an alternative way to pass a command line argument to particular tests. The method below uses a fixture and skips the test if the fixture is specified but the argument is not:

test.py:

def test_name(name):
    assert name == 'almond'

conftest.py:

import pytest

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

@pytest.fixture(scope='session')
def name(request):
    name_value = request.config.option.name
    if name_value is None:
        pytest.skip()
    return name_value

Examples:

$ py.test tests/test.py
=========================== test session starts ============================
platform linux -- Python 3.7.1, pytest-4.0.0, py-1.7.0, pluggy-0.8.0
rootdir: /home/ipetrik/dev/pytest_test, inifile:
collected 1 item

tests/test.py s                                                      [100%]

======================== 1 skipped in 0.06 seconds =========================

$ py.test tests/test.py --name notalmond
=========================== test session starts ============================
platform linux -- Python 3.7.1, pytest-4.0.0, py-1.7.0, pluggy-0.8.0
rootdir: /home/ipetrik/dev/pytest_test, inifile:
collected 1 item

tests/test.py F                                                      [100%]

================================= FAILURES =================================
________________________________ test_name _________________________________

name = 'notalmond'

    def test_name(name):
>       assert name == 'almond'
E       AssertionError: assert 'notalmond' == 'almond'
E         - notalmond
E         ? ---
E         + almond

tests/test.py:5: AssertionError
========================= 1 failed in 0.28 seconds =========================

$ py.test tests/test.py --name almond
=========================== test session starts ============================
platform linux -- Python 3.7.1, pytest-4.0.0, py-1.7.0, pluggy-0.8.0
rootdir: /home/ipetrik/dev/pytest_test, inifile:
collected 1 item

tests/test.py .                                                      [100%]

========================= 1 passed in 0.03 seconds =========================

Solution 4

All you have to do is use pytest_addoption() in conftest.py and finally use request fixture:

# conftest.py

from pytest import fixture


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

@fixture()
def name(request):
    return request.config.getoption("--name")

And now you can run your test

def my_test(name):
    assert name == 'myName'

using:

pytest --name myName

Solution 5

It's a bit of a workaround but it'll get the parameters into the test. Depending on the requirements, it could be enough.

def print_name():
    import os
    print(os.environ['FILENAME'])
    pass

and then run the tests from the command-line:

FILENAME=/home/username/decoded.txt python3 setup.py test --addopts "-svk print_name"
Share:
99,340
ashish sarkar
Author by

ashish sarkar

Updated on July 08, 2022

Comments

  • ashish sarkar
    ashish sarkar almost 2 years

    I have a code and I need to pass the arguments like name from terminal. Here is my code and how to pass the arguments. I am getting a "File not found" kind error that I don't understand.

    I have tried the command in the terminal: pytest <filename>.py -almonds I should get the name printed as "almonds"

    @pytest.mark.parametrize("name")
    def print_name(name):
        print ("Displaying name: %s" % name)
    
  • pavel_orekhov
    pavel_orekhov about 5 years
    What is @pytest.mark.unit? Why do you use it? It seems that your code works without it, can I omit it?
  • clay
    clay about 5 years
    Don't use it. I removed it from the answer. In the past, it was supported and even recommended in older versions of pytest. In newer versions of pytest, it has been removed and it isn't supported.
  • Roelant
    Roelant almost 5 years
    What happens when you use test classes? :)
  • ged
    ged over 4 years
    python3 -m pytest test.py --name qwe gives error: pytest.py: error: unrecognized arguments: --name qwe. I have no py.test, what should I do in this case, could you please clarify?
  • ipetrik
    ipetrik over 4 years
    @ged - calling it the way you called it works for me. Please note that you should have two files - conftest.py and test.py. I have edited the answer to make this more clear.
  • dor00012
    dor00012 almost 4 years
    Can you also please point out how to add an argument to the list of test "fixturenames", as you said is needed in your answer.
  • dor00012
    dor00012 almost 4 years
    One can see an explanation for pytest_generate_tests on pytest documentation
  • tash
    tash over 3 years
    Does anyone know how to add multiple arguments? I am guessing metafunc.parametrize("name", [option_value]) has to be changed.
  • Gulzar
    Gulzar over 2 years
    ERROR: file or directory not found: abc
  • ryanjdillon
    ryanjdillon over 2 years
    I followed this pattern, and in my case also added a pytest mark @pytest.mark.model_diagnostics to delineate those tests that require an input, e.g. pytest -m model_diagnostics --fp-model=./model.h5. This also requires "registering" of your mark, for example in your pytest.ini.