Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I set sys.argv so I can unit test it?

Tags:

python

I would like to set

sys.argv 

so I can unit test passing in different combinations. The following doesn't work:

#!/usr/bin/env python import argparse, sys def test_parse_args():     global sys.argv     sys.argv = ["prog", "-f", "/home/fenton/project/setup.py"]     setup = get_setup_file()     assert setup == "/home/fenton/project/setup.py" def get_setup_file():     parser = argparse.ArgumentParser()     parser.add_argument('-f')     args = parser.parse_args()     return args.file if __name__ == '__main__':     test_parse_args() 

Then running the file:

pscripts % ./test.py                                                                                              File "./test.py", line 4     global sys.argv               ^ SyntaxError: invalid syntax pscripts %   
like image 907
ftravers Avatar asked Sep 07 '13 02:09

ftravers


People also ask

How do I give SYS argv?

To use, sys. argv in a Python script, we need to impo r t the sys module into the script. Like we import all modules, "import sys" does the job. Ideally, we want this at the top of the script, but anywhere before we use the sys.

How use SYS argv module in Python?

argv() is an array for command line arguments in Python. To employ this module named “ sys ” is used. sys. argv is similar to an array and the values are also retrieved like Python array.

How do I run a unit test from command-line in Python?

The command to run the tests is python -m unittest filename.py . In our case, the command to run the tests is python -m unittest test_utils.py .


2 Answers

Changing sys.argv at runtime is a pretty fragile way of testing. You should use mock's patch functionality, which can be used as a context manager to substitute one object (or attribute, method, function, etc.) with another, within a given block of code.

The following example uses patch() to effectively "replace" sys.argv with the specified return value (testargs).

try:     # python 3.4+ should use builtin unittest.mock not mock package     from unittest.mock import patch except ImportError:     from mock import patch  def test_parse_args():     testargs = ["prog", "-f", "/home/fenton/project/setup.py"]     with patch.object(sys, 'argv', testargs):         setup = get_setup_file()         assert setup == "/home/fenton/project/setup.py" 
like image 80
Jason Antman Avatar answered Sep 24 '22 14:09

Jason Antman


test_argparse.py, the official argparse unittest file, uses several means of setting/using argv:

parser.parse_args(args) 

where args is a list of 'words', e.g. ['--foo','test'] or --foo test'.split().

old_sys_argv = sys.argv sys.argv = [old_sys_argv[0]] + args try:     return parser.parse_args() finally:     sys.argv = old_sys_argv 

This pushes the args onto sys.argv.

I just came across a case (using mutually_exclusive_groups) where ['--foo','test'] produces different behavior than '--foo test'.split(). It's a subtle point involving the id of strings like test.

like image 32
hpaulj Avatar answered Sep 24 '22 14:09

hpaulj