How Can I Test Whether My Code Is Throwing The Appropriate Argparse Exceptions?
Solution 1:
After a bit of hacking away I've found something that will pass testing. Suggestions to remove cruft welcome.
In my main program I defined parse_args
with some extra keyword args to be used for testing only.
defparse_args(args, prog = None, usage = None):
PARSER = argparse.ArgumentParser(prog=prog, usage=usage)
....
Then in the testing class for testing the parser, adding these parameters to suppress usage and help information on an error as much as possible.
classArgParseTestCase(unittest.TestCase):def__init__(self, *args, **kwargs):
self.testing_params = {'prog':'TESTING', 'usage':''}
super(ArgParseTestCase, self).__init__(*args, **kwargs)
In the testing file defined this context manager from this answer:
from contextlib import contextmanager
from io import StringIO
@contextmanagerdefcapture_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 then modified the test in my question above to be something like:
deftest_no_action_error(self):
'''Test if no action produces correct error'''with self.assertRaises(SystemExit) as cm, capture_sys_output() as (stdout, stderr):
args = parse_args([' '], **self.testing_params)
self.assertEqual(2, cm.exception.code)
self.assertEqual('usage: \n TESTING: error: No action requested, add -process or -upload',
stderr.getvalue())
Now the extra text at the start of the assertEqual
isn't pretty... but the test passes so I'm happy.
Solution 2:
test/test_argparse.py
does some of this kind of testing:
For example:
classTestArgumentTypeError(TestCase):
deftest_argument_type_error(self):
defspam(string):
raise argparse.ArgumentTypeError('spam!')
parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
parser.add_argument('x', type=spam)
with self.assertRaises(ArgumentParserError) as cm:
parser.parse_args(['XXX'])
self.assertEqual('usage: PROG x\nPROG: error: argument x: spam!\n',
cm.exception.stderr)
But the key to this the ErrorRaisingArgumentParser
subclass defined near the start of the file.
classErrorRaisingArgumentParser(argparse.ArgumentParser):defparse_args(self, *args, **kwargs):
parse_args = super(ErrorRaisingArgumentParser, self).parse_args
return stderr_to_parser_error(parse_args, *args, **kwargs)
defexit(self, *args, **kwargs):
exit = super(ErrorRaisingArgumentParser, self).exit
return stderr_to_parser_error(exit, *args, **kwargs)
deferror(self, *args, **kwargs):
error = super(ErrorRaisingArgumentParser, self).error
return stderr_to_parser_error(error, *args, **kwargs)
See that file for details. With stderr redirection it gets a bit complicated. Maybe more than really needed.
Solution 3:
The easiest way using pytest
would be the following:
with pytest.raises(SystemExit) as e:
parse_args(...)
assertisinstance(e.value.__context__, argparse.ArgumentError)
assert'expected err msg'in e.value.__context__.message
We need this workaround as argparse will exit error code 2 which means that a SystemExit
will be raised.
Post a Comment for "How Can I Test Whether My Code Is Throwing The Appropriate Argparse Exceptions?"