try tipos excepciones diferentes python testing nose

python - tipos - ¿Cómo deberíamos probar las excepciones con la nariz?



excepciones en python (6)

No sé por qué no está aquí todavía, pero existe una manera más:

import unittest class TestCase(unittest.TestCase): def testKeyError(self): d = dict() with self.assertRaises(KeyError): d[1]

Estoy probando excepciones con la nariz. Aquí hay un ejemplo:

def testDeleteUserUserNotFound(self): "Test exception is raised when trying to delete non-existent users" try: self.client.deleteUser(''10000001-0000-0000-1000-100000000000'') # make nose fail here except UserNotFoundException: assert True

El aserto se ejecuta si se genera la excepción, pero si no se produce una excepción, no se ejecutará.

¿Hay algo que pueda poner en la línea comentada de arriba para que, si no se produce una excepción, informe un error?


No sé qué es la nariz, pero ha intentado usar ''else'' después de la cláusula de excepción. Es decir

else: assert False


Recomiendo usar assert_raises y assert_raises_regexp de nose.tools , que duplican el comportamiento de assertRaises y assertRaisesRegexp de unittest.TestCase . Estas permiten el uso de la misma funcionalidad proporcionada por unittest.TestCase en las suites de prueba que en realidad no usan la clase unittest.TestCase .

Me parece que @raises es un instrumento demasiado contundente. Aquí está el código que ilustra el problema:

from nose.tools import * something = ["aaa", "bbb"] def foo(x, source=None): if source is None: source = something return source[x] # This is fine @raises(IndexError) def test1(): foo(3) # This is fine. The expected error does not happen because we made # a mistake in the test or in the code. The failure indicates we made # a mistake. @raises(IndexError) def test2(): foo(1) # This passes for the wrong reasons. @raises(IndexError) def test3(): source = something[2] # This is the line that raises the exception. foo(10, source) # This is not tested. # When we use assert_raises, we can isolate the line where we expect # the failure. This causes an error due to the exception raised in # the first line of the function. def test4(): source = something[2] with assert_raises(IndexError): foo(10, source)

test3 pasa, pero no porque foo haya generado la excepción que esperábamos, sino porque el código que configura los datos para que foo falle con la misma excepción. test4 muestra cómo se puede escribir la prueba utilizando assert_raises para probar realmente lo que queremos hacer. El problema en la primera línea causará que Nose informe un error y luego podemos reescribir la prueba para que esa línea finalmente pueda probar lo que significamos probar.

@raises no permite probar el mensaje asociado con la excepción. Cuando ValueError , solo para tomar un ejemplo, usualmente quiero subirlo con un mensaje informativo. Aquí hay un ejemplo:

def bar(arg): if arg: # This is incorrect code. raise ValueError("arg should be higher than 3") if arg >= 10: raise ValueError("arg should be less than 10") # We don''t know which of the possible `raise` statements was reached. @raises(ValueError) def test5(): bar(10) # Yes, we''re getting an exception but with the wrong value: bug found! def test6(): with assert_raises_regexp(ValueError, "arg should be less than 10"): bar(10)

test5 que usa @raises pasará, pero pasará por la razón equivocada. test6 realiza una prueba más test6 que revela que el ValueError generado no fue el que queríamos.


Utilice assert_raises :

from nose.tools import assert_raises our_method = self.client.deleteUser arg1 = ''10000001-0000-0000-1000-100000000000'' expected_exception = UserNotFoundException assert_raises(expected_exception, our_method, arg1)

Usar la prueba y captura en sus pruebas parece ser una mala práctica (la mayoría de los casos).

No hay documentación específica en la nariz porque básicamente es solo una envoltura alrededor de assertRaises (ref. ¿Cómo usar assert_raises de nose? )


nose proporciona herramientas para probar excepciones (como hace unittest). Pruebe este ejemplo (y lea sobre las otras herramientas en Nose Testing Tools

from nose.tools import * l = [] d = dict() @raises(Exception) def test_Exception1(): ''''''this test should pass'''''' l.pop() @raises(KeyError) def test_Exception2(): ''''''this test should pass'''''' d[1] @raises(KeyError) def test_Exception3(): ''''''this test should fail (IndexError raised but KeyError was expected)'''''' l.pop() def test_Exception4(): ''''''this test should fail with KeyError'''''' d[1]

Creo que esta es la forma correcta que estaba buscando porque le permite ser específico acerca de las excepciones que espera o desea. Entonces realmente provocas el error para ver que genera la excepción correcta. Y luego dejas que la nariz evalúe el resultado. (¡Ponga la menor lógica posible en las pruebas unitarias!)


def testDeleteUserUserNotFound(self): "Test exception is raised when trying to delete non-existent users" try: self.client.deleteUser(''10000001-0000-0000-1000-100000000000'') assert False # <--- except UserNotFoundException: assert True

La semántica de try / except implica que el flujo de ejecución deja el bloque try en una excepción, por lo que assert False no se ejecutará si se produce una excepción. Además, la ejecución no volverá a entrar en el bloque de try una vez que el bloque de except haya terminado de ejecutarse, por lo que no debería tener problemas.

↓ (statements) ↓ exception (try) ↚──────────→ (except) ↓ │ (statements) ←───────────┘ ↓