11

I am able to pass command line arguments when running

python <filename>.py arg1

But when am trying to pass the command line arguments for running pytest it fails and gives error as below. Can you please advise.

pytest <filename>.py arg1
ERROR: file not found: arg1

EDIT:

For example am thinking of using it this way assuming I have passed an argument and am reading it via sys.argv:

import sys
arg = sys.argv[3]
def f():
    return 3

def test_function():
    assert f() == arg
Klaus D.
  • 13,874
  • 5
  • 41
  • 48
anukb
  • 183
  • 1
  • 1
  • 10
  • What do you need it for? – Klaus D. Mar 14 '17 at 05:14
  • I want to pass the data and store it to a variable in the script. Is it possible..? thanks. – anukb Mar 14 '17 at 05:21
  • You shouldn't parameterize your tests like this. Test should be as self contained as possible. If you have to test `argv`s for you application, mock them. – Klaus D. Mar 14 '17 at 05:32
  • Thanks agreed. I just wanted to try if its possible to pass arguments that way. Please let me know if at all its possible any way. – anukb Mar 14 '17 at 05:35
  • Helpful solution found here based on the pytest doc: https://stackoverflow.com/a/76813725/9257803 – Arthur knn Aug 01 '23 at 16:49

3 Answers3

8

Your pytest <filename>.py arg1 command is trying to call pytest on two modules <filename>.py and arg1 , But there is no module arg1.

If you want to pass some argument before running pytest then run the pytest from a python script after extracting your variable.

As others suggested though you would probably want to parameterize your tests in some other way, Try:Parameterized pytest.

# run.py
import pytest
import sys

def main():
    # extract your arg here
    print('Extracted arg is ==> %s' % sys.argv[2])
    pytest.main([sys.argv[1]])

if __name__ == '__main__':
    main()

call this using python run.py filename.py arg1

Kashif Siddiqui
  • 1,476
  • 14
  • 26
  • 1
    Unfortunately am getting the same error as I was getting before - Error: File not found – anukb Mar 14 '17 at 06:23
  • Can you tell me what you meant by **extract your arg here – anukb Mar 14 '17 at 06:27
  • @anukb I've updated the code, But I'm not sure how many args you will pass. You can check out http://stackoverflow.com/questions/4117530/sys-argv1-meaning-in-script for more details about sys arg – Kashif Siddiqui Mar 14 '17 at 07:09
5

Here's the method I just cooked up from reading the parameterized pytest docs and hacking for a while... I don't know how stable or good it is going to be overall since I just got it working. I did however check that HTML coverage generation works with this method.

# this is just so we can pass --server and --port from the pytest command-line
def pytest_addoption(parser):
    ''' attaches optional cmd-line args to the pytest machinery '''
    parser.addoption("--server", action="append", default=[], help="real server hostname/IP")
    parser.addoption("--port", action="append", default=[], help="real server port number")
def pytest_generate_tests(metafunc):
    ''' just to attach the cmd-line args to a test-class that needs them '''
    server_from_cmd_line = metafunc.config.getoption("server")
    port_from_cmd_line = metafunc.config.getoption("port")
    print('command line passed for --server ({})'.format(server_from_cmd_line))
    print('command line passed for --port ({})'.format(port_from_cmd_line))
    # check if this function is in a test-class that needs the cmd-line args
    if server_from_cmd_line and port_from_cmd_line and hasattr(metafunc.cls, 'real_server'):
        # now set the cmd-line args to the test class
        metafunc.cls.real_server = server_from_cmd_line[0]
        metafunc.cls.real_port = int(port_from_cmd_line[0])


class TestServerCode(object):
    ''' test-class that might benefit from optional cmd-line args '''
    real_server=None
    real_port = None

    def test_valid_string(self):
        assert self.real_server!=None
        assert self.real_port!=None

    def test_other(self):
        from mypackage import my_server_code
        if self.real_server !=  None:
            assert "couldn\'t find host" not in my_server_code.version(self.real_server, self.real_port)
  • then run (with HTML coverage, for example) with:

    • pytest tests\test_junk.py --server="abc" --port=123 --cov-report html --cov=mypackage
nmz787
  • 1,960
  • 1
  • 21
  • 35
  • Good tip, thanks. I used this method to allow passing in a username/password on the command line when running tests. Previously, I had to hardcode credentials in source code, which I really hate. One negative side-effect is that the username/password is printed to terminal when executing the tests. I don't like this, but it's acceptable considering the console already has the credentials visible when executing Pytest with the additional options (username, password). – Jeff Wright May 15 '20 at 23:45
  • Add a dummy account? Then passwords appearing wont be much of an issue – Abdur-Rahmaan Janhangeer Oct 18 '20 at 03:43
2

It seems monkeypatch also works.

Example:

import sys

def test_example(monkeypatch):
    monkeypatch.setattr(sys, 'argv', ['/path/to/binary', 'opt1', '...'])
    assert f() == '...'

def test_another():
    # sys.argv is not modified here
    assert f() != '...'
bufh
  • 3,153
  • 31
  • 36