¿Cómo utilizar correctamente assertRaises () de unit-testing con objetos NoneType?

Hice un caso de prueba simple:

def setUp(self): self.testListNone = None def testListSlicing(self): self.assertRaises(TypeError, self.testListNone[:1]) 

y estoy esperando que la prueba pase, pero estoy recibiendo 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 la excepción TypeError se producirá?

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

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

Si está usando python2.6 de otra manera que no sea la dada hasta ahora, debe usar unittest2, que es un puerto posterior de unittest nueva característica de python2.6, y puede hacer que funcione con el código anterior.

NB: soy un gran fan de la nueva función (SkipTest, prueba de descubrimiento …) 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 unittest viene en python2.6 <.

El problema es que TypeError se assertRaises ‘antes de’ que se llame a assertRaises ya que los argumentos para assertRaises deben evaluarse antes de que se pueda llamar al método. Necesitas pasar una expresión lambda como:

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

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

 self.assertRaises(TypeError, test_function, args) 

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

El problema con self.testListNone[:1] es que Python evalúa la expresión inmediatamente, antes de assertRaises método assertRaises . La razón por la que test_function y args se pasan como argumentos separados a self.assertRaises es permitir que assertRaises llame a test_function(args) desde dentro de un bloque try...except , lo que permite que assertRaises la excepción.

Ya que ha definido self.testListNone = None , y necesita una función para llamar, puede usar operator.itemgetter de esta manera:

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

ya que

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

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

Fragmento completo se vería como el siguiente. Expande la respuesta de @mouad a la afirmación sobre el mensaje de error (o en general, la representación de sus 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))