I have some code that parses command line options using argparse.
For example:
# mycode.py
import argparse
def parse_args():
parser = argparse.ArgumentParser('my code')
# list of arguments
# ...
# ...
return vars(parser.parse_args())
if __name__ == "__main__":
parse_args()
I would like to use unittest to check the output of the help function. I also don't want to change the actual code unless there is no other solution.
The help action has a SystemExit
call built into it after printing to stdout, so I have had to try and catch it in the unittest.
Here is my unittest code with the following steps:
1) Set the sys.argv
list to include the -h
flag.
2) Wrap the function call in a context manager to prevent the SystemExit
being viewed as an error.
3) Switch the sys.stdout
temporarily to an io.StringIO
object so I can inspect it without having it print to screen.
4) Call the function in a try...finally
block so the SystemExit
isn't fatal.
5) Switch sys.stdout
back to the real stdout
.
6) Open a file to which I had previously saved the help text (by entering python mycode.py -h > help_out.txt
in the terminal) to verify it is the same as the captured output from the StringIO
.
import unittest
import mycode
import sys
import io
class TestParams(unittest.TestCase):
def setUp(self):
pass
def test_help(self):
args = ["-h"]
sys.argv[1:] = args
with self.assertRaises(SystemExit):
captured_output = io.StringIO()
sys.stdout = captured_output
try:
mycode.parse_args()
finally:
sys.stdout = sys.__stdout__
with open("help_out.txt", "r") as f:
help_text = f.read()
self.assertEqual(captured_output, help_text)
def tearDown(self):
pass
This code works, but the captured_output
StringIO
object is empty, so the test fails.
I am looking for an explanation as to what is going wrong with the captured output and/or an alternative solution.
I was very close. The captured_output
wasn't actually empty - I just wasn't accessing the contents correctly.
Substitute captured_output.get_value()
for captured_value
in my example code and it works perfectly.