argumentparser - arguments parser python
¿Cómo me burlo del método de Python OptionParser.error(), que hace un sys.exit()? (4)
Estoy tratando de probar un código de la unidad que se ve así:
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())
Con un código que se ve así:
@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)
Estoy usando Mock de Michael Foord , y nariz para ejecutar las pruebas.
Cuando realizo la prueba, obtengo:
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)
El problema es que OptionParser.error hace un sys.exit (2), y así que main () naturalmente depende de eso. Pero nosetest o unittest detecta el (esperado) sys.exit (2) y falla la prueba.
Puedo pasar la prueba agregando "return 2" en la llamada a parser.error () en main () y eliminando la llamada a sys.exit () de parser_error_mock (), pero me parece desagradable modificar el código bajo prueba para permitir que pase una prueba ¿Hay una mejor solución?
Actualización : la respuesta de df funciona, aunque la llamada correcta es "self.assertRaises (SystemExit, sut.main)".
Lo que significa que la prueba pasa el número que sea en sys.exit () en parser_error_mock (). ¿Hay alguna manera de probar el código de salida?
Por cierto, la prueba es más robusta si agrego:
self.assertEquals(optionparser_mock.method_calls, [(''add_option'', (''--foo'',), {''action'': ''store'', ''help'': ''The foo option is self-explanatory''}), (''parse_args'', (), {})])
al final.
Actualización 2 : puedo probar el código de salida reemplazando "self.assertRaises (SystemExit, sut.main)" con:
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'')
¿Esto funcionará en lugar de assertEquals
?
self.assertRaises(SystemExit, sut.main, 2)
Esto debería capturar la excepción SystemExit
y evitar que la secuencia de comandos finalice.
Agregue @raises
a su función de prueba. Es decir:
from nose.tools import raises
@raises(SystemExit)
@patch(''optparse.OptionParser'')
def test_main_with_missing_p4clientsdir_option(self, mock_optionparser):
# Setup
...
sut.main()
Como mencioné en mis actualizaciones a mi pregunta, tuve que modificar la respuesta de dF a:
self.assertRaises(SystemExit, sut.main)
... y se me ocurrió un fragmento más largo para probar el código de salida.
[Nota: acepté mi propia respuesta, pero borraré esta respuesta y aceptaré la de dF si actualiza la suya.]
Probablemente esta pregunta contenga alguna información nueva: