13

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
5
  • What do you need it for? Commented Mar 14, 2017 at 5:14
  • I want to pass the data and store it to a variable in the script. Is it possible..? thanks. Commented Mar 14, 2017 at 5:21
  • You shouldn't parameterize your tests like this. Test should be as self contained as possible. If you have to test argvs for you application, mock them. Commented Mar 14, 2017 at 5: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. Commented Mar 14, 2017 at 5:35
  • Helpful solution found here based on the pytest doc: stackoverflow.com/a/76813725/9257803 Commented Aug 1, 2023 at 16:49

3 Answers 3

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

Sign up to request clarification or add additional context in comments.

3 Comments

Unfortunately am getting the same error as I was getting before - Error: File not found
Can you tell me what you meant by **extract your arg here
@anukb I've updated the code, But I'm not sure how many args you will pass. You can check out stackoverflow.com/questions/4117530/sys-argv1-meaning-in-script for more details about sys arg
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

2 Comments

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).
Add a dummy account? Then passwords appearing wont be much of an issue
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() != '...'

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.