32 votes

Comment tester unitairement une méthode __init__() d'une classe python avec assertRaises() ?

J'ai un cours :

class MyClass:
def __init__(self, foo):
    if foo != 1:
        raise Error("foo is not equal to 1!")

et un test unitaire qui est censé s'assurer que l'arg incorrect passé au constructeur soulève correctement une erreur :

def testInsufficientArgs(self):
    foo = 0
    self.assertRaises((Error), myClass = MyClass(Error, foo))

Mais je comprends...

NameError: global name 'Error' is not defined

Pourquoi ? Où dois-je définir cet objet Erreur ? Je pensais qu'il était intégré comme type d'exception par défaut, non ?

29voto

Jerub Points 17488

Dans cet exemple, "Error" peut être n'importe quel objet d'exception. Je pense que vous avez peut-être lu un exemple de code qui l'utilisait comme un substitut métasyntaxique pour signifier "la classe d'exception appropriée".

La classe de base de toutes les exceptions est appelée "Exception", et la plupart de ses sous-classes sont des noms descriptifs du type d'erreur concerné, tels que "OSError", "ValueError", "NameError", "TypeError".

Dans ce cas, l'erreur appropriée est 'ValueError' (la valeur de foo était fausse, donc une ValueError). Je vous recommande de remplacer 'Error' par 'ValueError' dans votre script.

Voici une version complète du code que vous essayez d'écrire, je duplique tout parce que vous avez un argument mot-clé bizarre dans votre exemple original que vous semblez confondre avec une affectation, et j'utilise le nom de la fonction 'failUnless' parce que c'est le nom non aliasé de la fonction :

class MyClass:
    def __init__(self, foo):
        if foo != 1:
            raise ValueError("foo is not equal to 1!")

import unittest
class TestFoo(unittest.TestCase):
    def testInsufficientArgs(self):
        foo = 0
        self.failUnlessRaises(ValueError, MyClass, foo)

if __name__ == '__main__':
    unittest.main()

La sortie est :

.
----------------------------------------------------------------------
Ran 1 test in 0.007s

OK

Il y a un défaut dans la bibliothèque de tests unitaires 'unittest' que d'autres cadres de tests unitaires corrigent. Vous noterez qu'il est impossible d'accéder à l'objet d'exception depuis le contexte d'appel. Si vous voulez corriger cela, vous devrez redéfinir cette méthode dans une sous-classe de UnitTest :

Voici un exemple de son utilisation :

class TestFoo(unittest.TestCase):
    def failUnlessRaises(self, excClass, callableObj, *args, **kwargs):
        try:
            callableObj(*args, **kwargs)
        except excClass, excObj:
            return excObj # Actually return the exception object
        else:
            if hasattr(excClass,'__name__'): excName = excClass.__name__
            else: excName = str(excClass)
            raise self.failureException, "%s not raised" % excName

    def testInsufficientArgs(self):
        foo = 0
        excObj = self.failUnlessRaises(ValueError, MyClass, foo)
        self.failUnlessEqual(excObj[0], 'foo is not equal to 1!')

J'ai copié la fonction failUnlessRaises de unittest.py de python2.5 et l'ai légèrement modifiée.

6voto

Terhorst Points 907

Que dites-vous de ça ?

class MyClass:
    def __init__(self, foo):
        if foo != 1:
            raise Exception("foo is not equal to 1!")

import unittest

class Tests(unittest.TestCase):
    def testSufficientArgs(self):
        foo = 1
        MyClass(foo)

    def testInsufficientArgs(self):
        foo = 2
        self.assertRaises(Exception, MyClass, foo)

if __name__ == '__main__':
    unittest.main()

1voto

Jon Cage Points 14126

Je pense que vous pensez à Exception s. Remplacez le mot "erreur" dans votre description par "exception" et vous devriez être prêt :-)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X