¿Cómo se escribe una prueba unitaria que falla solo si una función no arroja una excepción esperada?¿Cómo se prueba que una función de Python arroja una excepción?
Respuesta
Uso TestCase.assertRaises
(o TestCase.failUnlessRaises
) del módulo unittest, por ejemplo:
import mymod
class MyTestCase(unittest.TestCase):
def test1(self):
self.assertRaises(SomeCoolException, mymod.myfunc)
Eche un vistazo al método assertRaises del módulo unittest
.
el código debe seguir este patrón (esto es una prueba de estilo módulo unittest):
def test_afunction_throws_exception(self):
try:
afunction()
except ExpectedException:
pass
except Exception as e:
self.fail('Unexpected exception raised:', e)
else:
self.fail('ExpectedException not raised')
En Python < 2.7 esta construcción es útil para verificar valores específicos en la excepción esperada. La función unittest assertRaises
solo comprueba si se produjo una excepción.
y el método self.fail toma solo un argumento – mdob
Esto parece demasiado complicado para probar si una función arroja una excepción. Debido a que cualquier excepción que no sea la excepción arrojará un error al realizar la prueba y no lanzará una excepción fallará la prueba, parece que la única diferencia es que si obtiene una excepción diferente con 'assertRaises' obtendrá un ERROR en lugar de un FAIL. – unflores
El código en mi respuesta anterior se puede simplificar a:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction)
Y si ACONFIG toma argumentos, sólo tiene que pasar ellos en assertRaises así:
def test_afunction_throws_exception(self):
self.assertRaises(ExpectedException, afunction, arg1, arg2)
¿Cómo maneja la Trazabilidad de la excepción que está presente en la consola? Es decir, ahora hay un rastreo en la prueba de otro modo aprobada. – MadPhysicist
@MadPhysicist No veo de qué estás hablando. Acabo de probar en Python 2.6 y 3.5, no se están imprimiendo Tracebacks en la consola. ¿Quizás está imprimiendo o registrando el rastreo en algún lugar del código? –
utilizo doctest [1 ] casi en todas partes porque me gusta el hecho de que documente y pruebe mis funciones al mismo tiempo.
Tener un vistazo a este código:
def throw_up(something, gowrong=False):
"""
>>> throw_up('Fish n Chips')
Traceback (most recent call last):
...
Exception: Fish n Chips
>>> throw_up('Fish n Chips', gowrong=True)
'I feel fine!'
"""
if gowrong:
return "I feel fine!"
raise Exception(something)
if __name__ == '__main__':
import doctest
doctest.testmod()
Si se pone este ejemplo en un módulo y ejecuta desde la línea de comandos son evaluados y controlados ambos casos de prueba.
[1] Python documentation: 23.2 doctest -- Test interactive Python examples
Me encanta el doctest, pero creo que complementa en lugar de reemplazar a unittest. – TimothyAWiseman
¿Es menos probable que juegue bien con la refactorización automática? Supongo que una herramienta de refactorización diseñada para python * debería * estar al tanto de las cadenas de documentos. ¿Alguien puede comentar desde su experiencia? – kdbanman
acabo de descubrir que la Mock library proporciona un método assertRaisesWithMessage() (en su subclase unittest.TestCase), que comprobar no sólo que se eleva la excepción esperada, pero también que es levantado con el mensaje esperado:
from testcase import TestCase
import mymod
class MyTestCase(TestCase):
def test1(self):
self.assertRaisesWithMessage(SomeCoolException,
'expected message',
mymod.myfunc)
Desafortunadamente, ya no lo proporciona ... Pero la respuesta anterior de @Art (http://stackoverflow.com/a/3166985/1504046) da el mismo resultado – Rmatt
Como Python 2.7 se puede usar gestor de contexto para obtener una bodega del objeto real Excepción lanzada:
import unittest
def broken_function():
raise Exception('This is broken')
class MyTestCase(unittest.TestCase):
def test(self):
with self.assertRaises(Exception) as context:
broken_function()
self.assertTrue('This is broken' in context.exception)
if __name__ == '__main__':
unittest.main()
http://docs.python.org/dev/library/unittest.html#unittest.TestCase.assertRaises
En Python 3.5, hay que envolver context.exception
en str
, de lo contrario obtendrá un TypeError
self.assertTrue('This is broken' in str(context.exception))
Estoy usando Python 2.7.10, y el arriba no funciona; 'context.exception' no da el mensaje; es un tipo. – LateCoder
También en Python 2.7 (al menos en mi versión 2.7.6) usando 'import unittest2', necesitas usar' str() ', es decir' self.assertTrue ('Esto está roto' en str (context.exception)) ' . –
Dos cosas: 1. Puede usar assertIn en lugar de assertTrue. P.ej. self.assertIn ('Esto está roto', context.exception) 2. En mi caso, usando 2.7.10, context.exception parece ser una matriz de caracteres. Usar str no funciona. Terminé haciendo esto: '' .join (context.exception) Por lo tanto, juntar: self.assertIn ('Esto está roto', '' .join (context.exception)) – blockcipher
Usted puede utilizar assertRaises del módulo unittest
import unittest
class TestClass():
def raises_exception(self):
raise Exception("test")
class MyTestCase(unittest.TestCase):
def test_if_method_raises_correct_exception(self):
test_class = TestClass()
# note that you dont use() when passing the method to assertRaises
self.assertRaises(Exception, test_class.raises_exception)
de: http://www.lengrand.fr/2011/12/pythonunittest-assertraises-raises-error/
Primero, aquí está la función correspondiente (todavía dum: p) en el archivo dum_function.PY:
def square_value(a):
"""
Returns the square value of a.
"""
try:
out = a*a
except TypeError:
raise TypeError("Input should be a string:")
return out
Aquí está la prueba a realizar (sólo se inserta esta prueba):
import dum_function as df # import function module
import unittest
class Test(unittest.TestCase):
"""
The class inherits from unittest
"""
def setUp(self):
"""
This method is called before each test
"""
self.false_int = "A"
def tearDown(self):
"""
This method is called after each test
"""
pass
#---
## TESTS
def test_square_value(self):
# assertRaises(excClass, callableObj) prototype
self.assertRaises(TypeError, df.square_value(self.false_int))
if __name__ == "__main__":
unittest.main()
Ahora estamos listos para probar nuestra función! Esto es lo que sucede cuando se trata de ejecutar la prueba:
======================================================================
ERROR: test_square_value (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "test_dum_function.py", line 22, in test_square_value
self.assertRaises(TypeError, df.square_value(self.false_int))
File "/home/jlengrand/Desktop/function.py", line 8, in square_value
raise TypeError("Input should be a string:")
TypeError: Input should be a string:
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
El TypeError es actullay levantado, y genera un fallo de la prueba. El problema es que este es exactamente el comportamiento que queríamos: s.
Para evitar este error, sólo tiene que ejecutar la función usando lambda en la llamada de prueba:
self.assertRaises(TypeError, lambda: df.square_value(self.false_int))
La salida final:
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
perfecto!
... ¡y para mí también es perfecto!
Thansk mucho el Sr. Julien Lengrand-Lambert
Solo una nota, no necesitas la lambda. La línea 'self.assertRaises (TypeError, df.square_value (self.false_int))' llama al método y devuelve el resultado. Lo que quiere es pasar el método y cualquier argumento y dejar que la prueba unit lo llame: 'self.assertRaises (TypeError, df.square_value, self.false_int)' –
Usted puede construir su propia contextmanager
para comprobar si se produce la excepción.
import contextlib
@contextlib.contextmanager
def raises(exception):
try:
yield
except exception as e:
assert True
else:
assert False
Y entonces usted puede utilizar raises
así:
with raises(Exception):
print "Hola" # Calls assert False
with raises(Exception):
raise Exception # Calls assert True
Si está utilizando pytest
, esto se implementa ya. Usted puede hacer pytest.raises(Exception)
:
Ejemplo:
def test_div_zero():
with pytest.raises(ZeroDivisionError):
1/0
Y el resultado:
[email protected]$ py.test
================= test session starts =================
platform linux2 -- Python 2.6.6 -- py-1.4.20 -- pytest-2.5.2 -- /usr/bin/python
collected 1 items
tests/test_div_zero.py:6: test_div_zero PASSED
¿Cómo se prueba que una función de Python lanza una excepción?
¿Cómo se escribe una prueba que falla solo si una función no arroja una excepción esperada?
respuesta corta:
utilizar el método de self.assertRaises
como un gestor de contexto:
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
Demostración
El enfoque de mejores prácticas es bastante fácil de demostrar en un terminal de Python.
El unittest
biblioteca
En Python 2.7 o 3:
import unittest
En Python 2.6, se puede instalar un backport de unittest
la biblioteca de 2,7, llamados unittest2, y justo como alias que unittest
:
import unittest2 as unittest
ejemplo se comprueba
Ahora, pegue en su shell de Python la siguiente prueba de seguridad de tipo de Python:
class MyTestCase(unittest.TestCase):
def test_1_cannot_add_int_and_str(self):
with self.assertRaises(TypeError):
1 + '1'
def test_2_cannot_add_int_and_str(self):
import operator
self.assertRaises(TypeError, operator.add, 1, '1')
La prueba uno usa assertRaises
como gestor de contexto, lo que garantiza que el error se capta y se limpia correctamente, mientras se graba.
También podríamos escribirlo sin gestor de contexto, ver prueba dos. El primer argumento sería el tipo de error que espera plantear, el segundo argumento, la función que está probando y los argumentos restantes y los argumentos de palabras clave se pasarán a esa función.
Creo que es mucho más simple, legible y fácil de mantener el uso del gestor de contexto.
Ejecución de las pruebas
Para ejecutar las pruebas:
unittest.main(exit=False)
En Python 2.6, es probable que need the following:
unittest.TextTestRunner().run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
Y su terminal debe emitir el siguiente:
..
----------------------------------------------------------------------
Ran 2 tests in 0.007s
OK
<unittest2.runner.TextTestResult run=2 errors=0 failures=0>
Y vemos que, como esperamos, intentar agregar un 1
y un resultado '1'
en un TypeError
.
Para una salida más prolija, intente esto:
unittest.TextTestRunner(verbosity=2).run(unittest.TestLoader().loadTestsFromTestCase(MyTestCase))
- 1. ¿Cómo puedo afirmar que un método asíncrono C# arroja una excepción en una prueba unitaria?
- 2. Prueba si la propiedad arroja una excepción con nunit
- 3. ¿Se llama a tearDown si el caso de prueba arroja una excepción? (JUnit)
- 4. ¿Por qué XmlSerializer.Deserialize arroja una excepción System.IO.FileLoadException?
- 5. Afirmando que una función arroja excepciones con Qunit
- 6. Python: prueba que se realiza correctamente cuando no se produce una excepción
- 7. declara que un método siempre arroja una excepción?
- 8. ¿Cómo puedo escribir una prueba para manejar una excepción esperada?
- 9. Java URLDecoder arroja una excepción cuando se utiliza con una cadena que contiene un%
- 10. Cómo afirmar que una función no genera una excepción
- 11. ¿Cómo puedo encontrar una lista de todas las excepciones que arroja una función de biblioteca dada en Python?
- 12. Manejo de una excepción de Python que se produce dentro de una cláusula de excepción
- 13. Python - probar una propiedad lanza excepción
- 14. CPPUnit implementa una prueba para una excepción
- 15. Pasar una prueba de unidad de Python si no se produce una excepción
- 16. Python list.index arroja una excepción cuando no se encuentra el índice
- 17. Cómo evitar que se anule una función en python
- 18. La prueba de unidad arroja una excepción pero no puede ver el mensaje
- 19. BeginInvoke arroja la excepción
- 20. TransactionScope arroja la excepción
- 21. La creación de un Mutex arroja una excepción DirectoryNotFoundException
- 22. ¿Qué sucede cuando un subproceso de .NET arroja una excepción?
- 23. Si 'Process.HasExited' arroja una excepción, ¿puedo suponer que el proceso se ha ido?
- 24. Cómo manejar un inicializador de campo final estático que arroja una excepción comprobada
- 25. El servidor arroja una excepción, el cliente malinterpreta como éxito
- 26. ¿Cómo invocar un método que arroja una excepción utilizando la reflexión de Java?
- 27. ¿Por qué esto arroja una excepción de valor NULO?
- 28. ¿Puedes verificar que se lanza una excepción con doctest en Python?
- 29. Eliminar un objeto de un diccionario mutable arroja una excepción
- 30. . Servicios de directorio de .Net arroja una extraña excepción
hay una manera de hacer lo contrario de esto? Al igual que falla solo si la función arroja la excepción? – BUInvent
@BUInvent, sí, está: https://stackoverflow.com/a/4319870/3405140 – moertel
Tenga en cuenta que para pasar argumentos a 'myfunc' debe agregarlos como argumentos a la llamada a assertRaises. Ver la respuesta de Daryl Spitzer. – cbron