how to pass command line argument from pytest to code

折月煮酒 提交于 2021-01-22 04:19:06

问题


I am trying to pass arguments from a pytest testcase to a module being tested. For example, using the main.py from Python boilerplate, I can run it from the command line as:

$ python3 main.py
usage: main.py [-h] [-f] [-n NAME] [-v] [--version] arg
main.py: error: the following arguments are required: arg
$ python3 main.py xx
hello world
Namespace(arg='xx', flag=False, name=None, verbose=0)

Now I am trying to do the same with pytest, with the following test_sample.py

(NOTE: the main.py requires command line arguments. But these arguments need to be hardcoded in a specific test, they should not be command line arguments to pytest. The pytest testcase only needs to send these values as command line arguments to main.main().)

import main
def test_case01():
    main.main()
    # I dont know how to pass 'xx' to main.py,
    # so for now I just have one test with no arguments

and running the test as:

pytest -vs test_sample.py

This fails with error messages. I tried to look at other answers for a solution but could not use them. For example, 42778124 suggests to create a separate file run.py which is not a desirable thing to do. And 48359957 and 40880259 seem to deal more with command line arguments for pytest, instead of passing command line arguments to the main code.

I dont need the pytest to take command line arguments, the arguments can be hardcoded inside a specific test. But these arguments need to be passed as arguments to the main code. Can you give me a test_sample.py, that calls main.main() with some arguments?


回答1:


A good practice might to have this kind of code, instead of reading arguments from main method.

# main.py
def main(arg1):
    return arg1

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='My awesome script')
    parser.add_argument('word', help='a word')
    args = parser.parse_args()
    main(args.word)

This way, your main method can easily be tested in pytest

import main
def test_case01():
    main.main(your_hardcoded_arg)

I am not sure you can call a python script to test except by using os module, which might be not a good practice




回答2:


If you can't modify the signature of the main method, you can use the monkeypatching technique to temporarily replace the arguments with the test data. Example: imagine writing tests for the following program:

import argparse


def main():
    parser = argparse.ArgumentParser(description='Greeter')
    parser.add_argument('name')
    args = parser.parse_args()
    return f'hello {args.name}'


if __name__ == '__main__':
    print(main())

When running it from the command line:

$ python greeter.py world
hello world

To test the main function with some custom data, monkeypatch sys.argv:

import sys
import greeter

def test_greeter(monkeypatch):
    with monkeypatch.context() as m:
        m.setattr(sys, 'argv', ['greeter', 'spam'])
        assert greeter.main() == 'hello spam'

When combined with the parametrizing technique, this allows to easily test different arguments without modifying the test function:

import sys
import pytest
import greeter

@pytest.mark.parametrize('name', ['spam', 'eggs', 'bacon'])
def test_greeter(monkeypatch, name):
    with monkeypatch.context() as m:
        m.setattr(sys, 'argv', ['greeter', name])
        assert greeter.main() == 'hello ' + name

Now you get three tests, one for each of the arguments:

$ pytest -v test_greeter.py

...

test_greeter.py::test_greeter[spam] PASSED
test_greeter.py::test_greeter[eggs] PASSED
test_greeter.py::test_greeter[bacon] PASSED


来源:https://stackoverflow.com/questions/54071312/how-to-pass-command-line-argument-from-pytest-to-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!