para - Prueba de unidad de Python: ejecutar automáticamente el depurador cuando falla una prueba
ejecutar python en servidor web (5)
¿Hay alguna manera de iniciar automáticamente el depurador en el punto en el que falla una prueba unitaria?
En este momento solo estoy usando pdb.set_trace () manualmente, pero esto es muy tedioso ya que tengo que agregarlo cada vez y sacarlo al final.
Por ejemplo:
import unittest
class tests(unittest.TestCase):
def setUp(self):
pass
def test_trigger_pdb(self):
#this is the way I do it now
try:
assert 1==0
except AssertionError:
import pdb
pdb.set_trace()
def test_no_trigger(self):
#this is the way I would like to do it:
a=1
b=2
assert a==b
#magically, pdb would start here
#so that I could inspect the values of a and b
if __name__==''__main__'':
#In the documentation the unittest.TestCase has a debug() method
#but I don''t understand how to use it
#A=tests()
#A.debug(A)
unittest.main()
import unittest
import sys
import pdb
import functools
import traceback
def debug_on(*exceptions):
if not exceptions:
exceptions = (AssertionError, )
def decorator(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
try:
return f(*args, **kwargs)
except exceptions:
info = sys.exc_info()
traceback.print_exception(*info)
pdb.post_mortem(info[2])
return wrapper
return decorator
class tests(unittest.TestCase):
@debug_on()
def test_trigger_pdb(self):
assert 1 == 0
Corregí el código para llamar a post_mortem en la excepción en lugar de set_trace.
Una opción simple es simplemente ejecutar las pruebas sin recolección de resultados y dejar que la primera excepción se cierre en la pila (para el manejo arbitrario post mortem) por ejemplo
unittest.findTestCases(__main__).debug()
Otra opción: addError
unittest.TextTestResult
''s addError
y addFailure
en un addFailure
de prueba de depuración para la depuración post_mortem inmediata (antes de tearDown()
) o para recopilar y manejar errores y retrotraves de una manera avanzada.
(No requiere marcos adicionales o un decorador adicional para los métodos de prueba)
Ejemplo básico:
import unittest, pdb
class TC(unittest.TestCase):
def testZeroDiv(self):
1 / 0
def debugTestRunner(post_mortem=None):
"""unittest runner doing post mortem debugging on failing tests"""
if post_mortem is None:
post_mortem = pdb.post_mortem
class DebugTestResult(unittest.TextTestResult):
def addError(self, test, err):
# called before tearDown()
traceback.print_exception(*err)
post_mortem(err[2])
super(DebugTestResult, self).addError(test, err)
def addFailure(self, test, err):
traceback.print_exception(*err)
post_mortem(err[2])
super(DebugTestResult, self).addFailure(test, err)
return unittest.TextTestRunner(resultclass=DebugTestResult)
if __name__ == ''__main__'':
##unittest.main()
unittest.main(testRunner=debugTestRunner())
##unittest.main(testRunner=debugTestRunner(pywin.debugger.post_mortem))
##unittest.findTestCases(__main__).debug()
Para aplicar la respuesta de @cmcginty a la nariz sucesora recomendada por la nariz 2 (disponible en los sistemas basados en Debian a través de apt-get install nose2
), puede apt-get install nose2
al depurador en caso de fallas y errores al llamar
nose2
en su directorio de prueba, y tener un .unittest.cfg
adecuado en su directorio de inicio o unittest.cfg
en el directorio del proyecto, como f.ex.
[debugger]
always-on = True
errors-only = False
Aquí hay una solución incorporada, sin módulos adicionales:
import unittest
import sys
import pdb
####################################
def ppdb(e=None):
"""conditional debugging
use with: `if ppdb(): pdb.set_trace()`
"""
return ppdb.enabled
ppdb.enabled = False
###################################
class SomeTest(unittest.TestCase):
def test_success(self):
try:
pass
except Exception, e:
if ppdb(): pdb.set_trace()
raise
def test_fail(self):
try:
res = 1/0
#note: a `nosetests --pdb` run will stop after any exception
#even one without try/except and ppdb() does not not modify that.
except Exception, e:
if ppdb(): pdb.set_trace()
raise
if __name__ == ''__main__'':
#conditional debugging, but not in nosetests
if "--pdb" in sys.argv:
print "pdb requested"
ppdb.enabled = not sys.argv[0].endswith("nosetests")
sys.argv.remove("--pdb")
unittest.main()
llámalo con python myunittest.py --pdb
y se detendrá. De lo contrario, no lo hará.