how to pass command line argument from pytest to code

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


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