¿Cómo usar correctamente el assertRaises() de pruebas unitarias con objetos NoneType? [duplicate]

1 minuto de lectura

Hice un caso de prueba simple:

def setUp(self):

  self.testListNone = None

def testListSlicing(self):

  self.assertRaises(TypeError, self.testListNone[:1])

y espero que pase la prueba, pero obtengo una excepción:

Traceback (most recent call last):

    self.assertRaises(TypeError, self.testListNone[:1])

TypeError: 'NoneType' object is unsubscriptable

Pensé que assertRaises pasará ya que se generará la excepción TypeError.

  • ongspxm.github.io/blog/2016/11/… Puede consultar este documento ya que él/ella ha explicado por qué usar un administrador de contexto/lambda para envolver el código

    – Sanjeev Shiva

    21 de abril de 2020 a las 11:33


avatar de usuario
moada

Si está usando python2.7 o superior, puede usar la capacidad de afirmaraumenta para ser utilizado como un administrador de contexto y hacer:

with self.assertRaises(TypeError):
    self.testListNone[:1]

Si está utilizando python2.6, otra forma además de la dada hasta ahora es usar unittest2 que es un puerto posterior de la nueva función unittest para python2.6, y puede hacer que funcione usando el código anterior.

NB: Soy un gran admirador de la nueva función (SkipTest, descubrimiento de pruebas…) de unittest, así que tengo la intención de usar unittest2 tanto como pueda. Aconsejo hacer lo mismo porque hay mucho más de lo que viene con unittest en python2.6 <.>

  • 2.7 o superior … ¿nos estás ocultando Python 2.8?

    –Robin De Schepper

    28 de marzo de 2021 a las 15:08

  • El código que menciona no parece ayudar con el problema de finalizar el script antes de que llegue la comparación de aserción. Todavía falla la prueba (usando python 3.10)

    – Asriel

    21 de diciembre de 2021 a las 15:44

el problema es el TypeError se levanta ‘antes’ assertRaises se llama desde los argumentos a assertRaises deben evaluarse antes de poder llamar al método. Tienes que pasar un lambda expresión como:

self.assertRaises(TypeError, lambda: self.testListNone[:1])

  • Probablemente la mejor respuesta

    – Christophe Roussy

    12 de julio de 2016 a las 13:18

  • ¿Me pueden ayudar en una pregunta relacionada? stackoverflow.com/questions/39909935/…

    –Eran Morad

    7 oct 2016 a las 17:11

  • La respuesta de @unutbu muestra cómo llamar assertRaises (no es necesario lambda)

    – scharfmn

    04/04/2018 a las 17:45

La forma habitual de uso assertRaises es llamar a una función:

self.assertRaises(TypeError, test_function, args)

para probar que la llamada a la función test_function(args) genera un TypeError.

el problema con self.testListNone[:1] es que Python evalúa la expresión inmediatamente, antes de que assertRaises se llama el método. Toda la razón por la cual test_function y args se pasa como argumentos separados a self.assertRaises es permitir assertRaises llamar test_function(args) desde dentro de un try...except bloquear, permitiendo assertRaises para capturar la excepción.

Ya que has definido self.testListNone = Noney necesita una función para llamar, puede usar operador.itemgetter como esto:

import operator
self.assertRaises(TypeError, operator.itemgetter, (self.testListNone,slice(None,1)))

ya que

operator.itemgetter(self.testListNone,slice(None,1))

es una forma larga de decir self.testListNone[:1]pero que separa la función (operator.itemgetter) de los argumentos.

  • Para un solo assertRaises, esta parece ser la mejor respuesta. Para un gran banco de pruebas basadas en excepciones (suponiendo que todas tengan el mismo tipo de excepción), with self.assertRaises(…) sería una buena opción.

    – usuario632657

    1 mayo 2014 a las 17:55

  • Sí, esta debería ser la respuesta correcta ya que en realidad explica el problema.

    -Henry Gomersall

    3 oct 2014 a las 14:59

  • Esta es definitivamente la respuesta correcta, lo que explica el problema.

    – Ismael

    11 de diciembre de 2014 a las 13:31

  • ¿Me pueden ayudar en una pregunta relacionada? stackoverflow.com/questions/39909935/…

    –Eran Morad

    7 oct 2016 a las 17:11

  • +1 Se puede simplificar a self.assertRaises(TypeError, self.testListNone.__getitem__, slice(None,1))porque operator.itemgetter agrega una pequeña complejidad inútil.

    – Hynekcer

    6 de abril de 2021 a las 12:31

El fragmento completo se vería así. Expande la respuesta de @mouad para afirmar el mensaje de error (o generalmente str representación de su args), que puede ser útil.

from unittest import TestCase


class TestNoneTypeError(TestCase):

  def setUp(self): 
    self.testListNone = None

  def testListSlicing(self):
    with self.assertRaises(TypeError) as ctx:
        self.testListNone[:1]
    self.assertEqual("'NoneType' object is not subscriptable", str(ctx.exception))

¿Ha sido útil esta solución?