I\'m writing test cases for argparse implementation. I intend to test \'-h\' feature. The following code does it. But it also outputs the usage for the script. Is there a wa
When testing for exception codes, use self.assertRaises() as a context manager; this gives you access to the raised exception, letting you test the .code
attribute:
with self.assertRaises(SystemExit) as cm:
arg_parse_obj.parse_known_args(['-h'])
self.assertEqual(cm.exception.code, 0)
To 'suppress' or test the output, you'll have to capture either sys.stdout
or sys.stderr
, depending on the argparse
output (help text goes to stdout
). You could use a context manager for that:
from contextlib import contextmanager
from StringIO import StringIO
@contextmanager
def capture_sys_output():
capture_out, capture_err = StringIO(), StringIO()
current_out, current_err = sys.stdout, sys.stderr
try:
sys.stdout, sys.stderr = capture_out, capture_err
yield capture_out, capture_err
finally:
sys.stdout, sys.stderr = current_out, current_err
and use these as:
with self.assertRaises(SystemExit) as cm:
with capture_sys_output() as (stdout, stderr):
arg_parse_obj.parse_known_args(['-h'])
self.assertEqual(cm.exception.code, 0)
self.assertEqual(stderr.getvalue(), '')
self.assertEqual(stdout.getvalue(), 'Some help value printed')
I nested the context managers here, but in Python 2.7 and newer you can also combine them into one line; this tends to get beyond the recommended 79 character limit in a hurry though.
Some variations on using ['-h']
include:
parser.print_help() # formats the help, prints it and exits
parser.format_help() # format the help without printing or exit
parser.exit # can be modified to not exit, such as for a parser subclass
parser.error # default print usage and call parser.exit
These are part of the public API.
The argparse
test file (test_argparse.py
) also gives ideas on how to test things. For many tests it uses an ArgumentParser
subclass that has its own error
method.
Mock could do this, allowing you the same functionality as Martijn Pieters' answer but without having to write your own function:
from unittest.mock import MagicMock, patch
argparse_mock = MagicMock()
with patch('argparse.ArgumentParser._print_message', argparse_mock):
with self.assertRaises(SystemExit) as cm:
arg_parse_obj.parse_known_args(['-h'])
patch also works as a decorator. If you have several instances where the argparse printing needs to be suppressed, you can do it as a decorator and avoid using a bunch of nested with statements.