Je suis en train de test unitaire du code qui ressemble à ceci:Comment est-ce que je me moque de la méthode Python OptionParser.error(), qui fait un sys.exit()?
def main():
parser = optparse.OptionParser(description='This tool is cool', prog='cool-tool')
parser.add_option('--foo', action='store', help='The foo option is self-explanatory')
options, arguments = parser.parse_args()
if not options.foo:
parser.error('--foo option is required')
print "Your foo is %s." % options.foo
return 0
if __name__ == '__main__':
sys.exit(main())
Avec le code qui ressemble à ceci:
@patch('optparse.OptionParser')
def test_main_with_missing_p4clientsdir_option(self, mock_optionparser):
#
# setup
#
optionparser_mock = Mock()
mock_optionparser.return_value = optionparser_mock
options_stub = Mock()
options_stub.foo = None
optionparser_mock.parse_args.return_value = (options_stub, sentinel.arguments)
def parser_error_mock(message):
self.assertEquals(message, '--foo option is required')
sys.exit(2)
optionparser_mock.error = parser_error_mock
#
# exercise & verify
#
self.assertEquals(sut.main(), 2)
J'utilise Michael Foord's Mock, et le nez pour exécuter les tests.
Quand je lance le test, je reçois:
File "/Users/dspitzer/Programming/Python/test-optparse-error/tests/sut_tests.py", line 27, in parser_error_mock
sys.exit(2)
SystemExit: 2
----------------------------------------------------------------------
Ran 1 test in 0.012s
FAILED (errors=1)
Le problème est que OptionParser.error fait un sys.exit (2), et ainsi de main() repose naturellement sur ce point. Mais nez ou unittest détecte le sys.exit (attendu) et échoue le test.
Je peux faire passer le test en ajoutant "return 2" sous l'appel parser.error() dans main() et en supprimant l'appel sys.exit() de parser_error_mock(), mais je trouve désagréable de modifier le code sous test pour permettre le passage d'un test. Y a-t-il une meilleure solution?
La mise à jour: df La réponse fonctionne, bien que l'appel correct soit "self.assertRaises (SystemExit, sut.main)".
Ce qui signifie que le test passe quel que soit le nombre dans sys.exit() dans parser_error_mock(). Est-il possible de tester le code de sortie?
BTW, le test est plus robuste si j'ajoute:
self.assertEquals(optionparser_mock.method_calls, [('add_option', ('--foo',), {'action': 'store', 'help': 'The foo option is self-explanatory'}), ('parse_args',(), {})])
à la fin.
Mise à jour 2: Je peux tester le code de sortie en remplaçant "self.assertRaises (SystemExit, sut.main)" avec:
try:
sut.main()
except SystemExit, e:
self.assertEquals(type(e), type(SystemExit()))
self.assertEquals(e.code, 2)
except Exception, e:
self.fail('unexpected exception: %s' % e)
else:
self.fail('SystemExit exception expected')
Les premiers assertEquals sur votre mise à jour 2 est inutile, puisque la « sauf » ligne ci-dessus il n'attraper des exceptions SystemExit. – rbp