estoy tratando de probar la unidad un código que se parece a esto:¿Cómo me burlo del método de Python OptionParser.error(), que hace 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())
Con el código que se parece a esto:
@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 Michael Foord's Mock, y la nariz para ejecutar las pruebas.
Cuando ejecuto la prueba, me sale:
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 hace un OptionParser.error sys.exit (2), y así main() de forma natural se basa en eso. Pero nosetest o unittest detecta el (esperado) sys.exit (2) y falla la prueba.
Puedo hacer que la prueba pase 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 la código bajo prueba para permitir que pase una prueba. ¿Hay una mejor solución?
Actualización: df La respuesta funciona, aunque la llamada correcta es "self.assertRaises (SystemExit, sut.main)".
Lo que significa que la prueba pasa cualquiera que sea el número en el 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 añado:
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 mediante la sustitución de "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')
La primera assertEquals en su Actualización 2 es innecesaria, ya que la línea "excepto" que se encuentra arriba solo capturará las excepciones de SystemExit. – rbp