How to pass arguments in pytest by command line

PythonTestingPytestCommand Line-Arguments

Python Problem Overview


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)

Python Solutions


Solution 1 - Python

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 - Python

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 - Python

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 - Python

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 - Python

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"

Solution 6 - Python

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 <filename>.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 - Python

> 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 8 - Python

Managed to get this to work with a Class of unittest.TestCase using answers here and https://docs.pytest.org/en/6.2.x/unittest.html

conftest.py:

import pytest

my_params = {
    "name": "MyName",
    "foo": "Bar",
}


def pytest_addoption(parser):
    for my_param_name, my_param_default in my_params.items():
        parser.addoption(f"--{my_param_name}", action="store", default=my_param_default)


@pytest.fixture()
def pass_parameters(request):
    for my_param in my_params:
        setattr(request.cls, my_param, request.config.getoption(f"--{my_param}"))

test_param.py

import unittest
import pytest


@pytest.mark.usefixtures("pass_parameters")
class TestParam(unittest.TestCase):
    def test_it(self):
        self.assertEqual(self.name, "MyName")

using:

pytest --name MyName

Solution 9 - Python

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionashish sarkarView Question on Stackoverflow
Solution 1 - PythonclayView Answer on Stackoverflow
Solution 2 - PythonOkkenView Answer on Stackoverflow
Solution 3 - PythonipetrikView Answer on Stackoverflow
Solution 4 - PythonGiorgos MyrianthousView Answer on Stackoverflow
Solution 5 - PythonkrissyView Answer on Stackoverflow
Solution 6 - PythonKir ChouView Answer on Stackoverflow
Solution 7 - PythonMohamed.AbdoView Answer on Stackoverflow
Solution 8 - PythoniliView Answer on Stackoverflow
Solution 9 - PythonMortenBView Answer on Stackoverflow