Angenommen, es gibt einen solchen Parser.
main.py
__version__ = '0.0.1'
def prepare_parser():
parser = ArgumentParser(description=(__doc__),
formatter_class=RawDescriptionHelpFormatter)
parser.add_argument('-d', '--debug', action='store_true',
help='Show debug log')
parser.add_argument('-v', '--version', action='version',
version=__version__,
help='Show version and exit')
return parser
Angenommen, Sie möchten testen, ob dieser Verison-Teil ordnungsgemäß verwendet werden kann.
Das Problem ist, dass parser.parse_args (['-v'])
dazu führt, dass SystemExit an diesem Punkt fliegt.
>>> from main import prepare_parser
>>> parser = prepare_parser()
>>> args = parser.parse_args(['-v'])
0.0.1
$ <--Der Interpreter wurde beendet, weil der Systemausgang fliegt.
Dies ist eine Spezifikation der Versionsaktion von argparse.
'version' - This expects a version= keyword argument in the add_argument() call, and prints version information and exits when invoked:
https://docs.python.org/3.6/library/argparse.html#action
Ich möchte nicht, dass sys.exit ()
mitten in einem Unit-Test beiläufig fliegt. Außerdem möchte ich bestätigen, dass die Version ordnungsgemäß ausgegeben wird.
Möglicherweise gibt es einen Patch (https://docs.python.jp/3/library/unittest.mock-examples.html#patch-decorators), aber wenn möglich, möchte ich den Inhalt von argparse als Black Box behandeln.
Versuche Folgendes.
tests.py
from contextlib import contextmanager
from io import StringIO
import unittest
import sys
from main import prepare_parser, __version__
@contextmanager
def capture_stdout(command, *args, **kwargs):
out, sys.stdout = sys.stdout, StringIO()
try:
command(*args, **kwargs)
finally:
sys.stdout.seek(0)
yield sys.stdout.read()
sys.stdout = out
class MyTest(unittest.TestCase):
def test_version(self):
parser = prepare_parser()
with self.assertRaises(SystemExit):
with capture_stdout(parser.parse_args, ['-v']) as output:
self.assertIsNotNone(output)
self.assertEqual(__version__, output.rstrip())
with self.assertRaises(SystemExit):
with capture_stdout(parser.parse_args,
['--version']) as output:
self.assertIsNotNone(output)
self.assertEqual(__version__, output.rstrip())
if __name__ == '__main__':
unittest.main()
Indem der Kontextmanager die Zeichenfolge ausgibt, die beim Überspringen der Ausnahme an stdout gesendet wurde, in der Hoffnung, dass der "SystemExit" übersprungen wird.
Ich bin gekommen, um testen zu können.
Beim Auskommentieren des optionalen Teils, der -v
usw. analysiert.
$ python tests.py
usage: tests.py [-h] [-d]
tests.py: error: unrecognized arguments: -v
F
======================================================================
FAIL: test_version (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "tests.py", line 26, in test_version
self.assertEqual(__version__, output.rstrip())
AssertionError: '0.0.1' != ''
- 0.0.1
+
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Wenn Sie einen Kommentar abgeben
$ python tests.py
.
----------------------------------------------------------------------
Ran 1 test in 0.001s
OK
Ich denke nicht, dass es die Art von Test ist, die ich machen möchte. Ist dieser Test anfällig ...? Ich bin mir nicht sicher.
Gibt es einen besseren Weg?
Recommended Posts