Python 如何通过命令行在pytest中传递参数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40880259/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 00:08:31  来源:igfitidea点击:

How to pass arguments in pytest by command line

pythonpytest

提问by ashish sarkar

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 -almondsI should get the name printed as "almonds"

我在终端中尝试了命令:pytest <filename>.py -almonds我应该将名称打印为“almonds”

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

回答by clay

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

在你的 pytest 测试中,不要使用@pytest.mark.parametrize

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

In conftest.py:

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

回答by Okken

Use the pytest_addoptionhook function in conftest.pyto define a new option.
Then use pytestconfigfixture in a fixture of your own to grab the name.
You can also use pytestconfigfrom 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.

使用pytest_addoption钩子函数 inconftest.py定义一个新选项。
然后pytestconfig在您自己的夹具中使用夹具来获取名称。
您也可以使用pytestconfigfrom 测试来避免编写自己的夹具,但我认为拥有自己的名称的选项会更简洁一些。

# 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
.

回答by ipetrik

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:

测试.py

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

conftest.py:

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

回答by Kir Chou

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
  • 注1:函数名必须以 test_
  • 注2:pytest 会重定向stdout (print),因此直接运行stdout 将无法在屏幕上显示任何结果。此外,在测试用例中无需在您的函数中打印结果。
  • 注3:pytest是python运行的模块,无法直接获取sys.argv


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)
...

回答by Mohamed.Abdo

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

参考: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

回答by Giorgos Myrianthous

All you have to do is use pytest_addoption()in conftest.pyand finally use requestfixture:

所有你需要做的是使用pytest_addoption()conftest.py最后使用request夹具:

# 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

回答by MortenB

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

如果你习惯了argparse,你可以按照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.