web-dev-qa-db-fra.com

Comment utiliser correctement assertRaises () avec les objets NoneType?

J'ai fait un cas de test simple:

def setUp(self):

  self.testListNone = None

def testListSlicing(self):

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

et je m'attends à ce que le test passe, mais j'obtiens une exception:

Traceback (most recent call last):

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

TypeError: 'NoneType' object is unsubscriptable

Je pensais que assertRaises passera puisque l'exception TypeError sera levée?

149
Andriusa

Si vous utilisez python2.7 ou supérieur, vous pouvez utiliser la capacité de assertRaises à utiliser en tant que gestionnaire de contexte et faire:

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

Si vous utilisez python2.6, vous pouvez utiliser nittest2 , qui est un port arrière de la nouvelle fonctionnalité unittest de python2.6, et vous pouvez le faire fonctionner avec le code ci-dessus. .

N.B: Je suis un grand fan de la nouvelle fonctionnalité (SkipTest, test discovery ...) de unittest alors je compte utiliser unittest2 autant que je peux. Je conseille de faire la même chose car il y a beaucoup plus que ce qui est unittest livré avec python2.6 <.

228
mouad

Le problème est que TypeError est soulevé 'avant' assertRaises soit appelé car les arguments de assertRaises doivent être évalués avant que la méthode puisse être appelée. Vous devez passer une expression lambda comme:

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

La manière habituelle d’utiliser assertRaises consiste à appeler une fonction:

self.assertRaises(TypeError, test_function, args)

pour tester que l'appel de fonction test_function (args) déclenche une erreur TypeError.

Le problème avec self.testListNone[:1] Est que Python évalue l'expression immédiatement, avant que la méthode assertRaises ne soit appelée. La raison principale pour laquelle test_function Et args est passé sous forme d'arguments distincts à self.assertRaises, ce qui permet à assertRaises d'appeler test_function(args) à partir d'un bloc try...except, permettant ainsi à assertRaises pour attraper l'exception.

Puisque vous avez défini self.testListNone = None Et que vous avez besoin d’une fonction à appeler, vous pouvez utiliser operator.itemgetter comme ceci:

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

puisque

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

est une manière longue de dire self.testListNone[:1], mais qui sépare la fonction (operator.itemgetter) des arguments.

78
unutbu

Un extrait complet ressemblerait à ce qui suit. Il étend la réponse de @ mouad à l'affirmation du message d'erreur (ou généralement str représentation de son args), ce qui peut être utile.

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))
5
saaj