How to pass arguments in pytest by command line

Python Programming

Question or problem about Python programming:

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 .py -almonds
I should get the name printed as “almonds”

@pytest.mark.parametrize("name")
def print_name(name):
    print ("Displaying name: %s" % name)

How to solve the problem:

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()
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 answers above do 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:


Pass different values to a test function, depending on command line options
Suppose we want to write a test that depends on a command line option. Here is a
basic pattern to achieve this:

# content of test_sample.py def test_answer(cmdopt): if cmdopt == "type1": print("first") elif cmdopt == "type2": print("second") assert 0 # to see what was printed For this to work we need to add a command line option and provide the cmdopt through a fixture function: # content of conftest.py import pytest def pytest_addoption(parser): parser.addoption( "--cmdopt", action="store", default="type1", help="my option: type1 or type2" ) @pytest.fixture def cmdopt(request): return request.config.getoption("--cmdopt") 

ref:
https://docs.pytest.org/en/latest/example/simple.html#pass-different-values-to-a-test-function-depending-on-command-line-options

Then you can call it with:

pytest --cmdopt type1 

Solution 6:

According to the official document, the mark decorator should look like below.

@pytest.mark.parametrize("arg1", ["StackOverflow"]) def test_mark_arg1(arg1): assert arg1 == "StackOverflow" #Success assert arg1 == "ServerFault" #Failed 

Run

python -m pytest .py 
  • Note1: function name must start with test_
  • Note2: pytest will redirect stdout (print), thus directly running stdout will not able to show any result on the screen. Also, there is no need to print result in your function in test cases.
  • Note3: pytest is a module run by python, which is not able to get sys.argv directly

If you really want to get outside configurable arguments, you should you implement that inside your script. (For example, loading content of file)

with open("arguments.txt") as f: args = f.read().splitlines() ... @pytest.mark.parametrize("arg1", args) ... 

Solution 7:

If you are used to argparse, you can prepare it the usual way in arparse

import argparse import sys DEFAULT_HOST = test99 #### for --host parameter ### def pytest_addoption(parser): parser.addoption("--host") # needed otherwhise --host will fail pytest parser = argparse.ArgumentParser(description="run test on --host") parser.add_argument('--host', help='host to run tests on (default: %(default)s)', default=DEFAULT_HOST) args, notknownargs = parser.parse_known_args() if notknownargs: print("pytest arguments? : {}".format(notknownargs)) sys.argv[1:] = notknownargs # then args.hosts holds you variable, while sys.args is parsed further with pytest. 

Hope this helps!