web-dev-qa-db-fra.com

Python unittest - l'opposé de assertRaises?

Je veux écrire un test pour établir qu'une exception n'est pas déclenchée dans une circonstance donnée. 

Il est facile de vérifier si une exception est est soulevée ...

sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath) 

... mais comment pouvez-vous faire le opposé

Quelque chose comme ça c'est ce que je cherche ...

sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath) 
278
glaucon
def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")
298
DGH

Bonjour - Je souhaite rédiger un test pour établir qu’une exception n’est pas déclenchée dans une situation donnée.

C'est l'hypothèse par défaut - les exceptions ne sont pas levées.

Si vous ne dites rien d'autre, c'est supposé dans chaque test.

Vous n'êtes pas obligé d'écrire une affirmation pour cela. 

54
S.Lott

Appelez simplement la fonction. S'il soulève une exception, le cadre de test unitaire le signalera comme une erreur. Vous voudrez peut-être ajouter un commentaire, par exemple:

sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
49
user9876

Je suis l’affiche originale et j’ai accepté la réponse ci-dessus de la part de DGH sans l’avoir utilisée au préalable dans le code. 

Une fois que j’ai utilisé, j’ai réalisé qu’il fallait faire quelques ajustements pour faire ce que j’avais besoin de faire (pour être juste envers DGH, il/elle a effectivement dit "ou quelque chose de similaire"!). 

Je pensais que ça valait la peine de poster le Tweak ici pour le bénéfice des autres:

    try:
        a = Application("abcdef", "")
    except pySourceAidExceptions.PathIsNotAValidOne:
        pass
    except:
        self.assertTrue(False)

Ce que j’essayais de faire ici était de faire en sorte que si on tentait d’instancier un objet Application avec un deuxième argument d’espaces, on déclenche la pySourceAidExceptions.PathIsNotAValidOne. 

Je crois que l'utilisation du code ci-dessus (basé fortement sur la réponse de DGH) le fera.

13
glaucon

Vous pouvez définir assertNotRaises en réutilisant environ 90% de l'implémentation originale de assertRaises dans le module unittest. Avec cette approche, vous vous retrouvez avec une méthode assertNotRaises qui, outre sa condition d'échec inversé, se comporte de manière identique à assertRaises.

TLDR et démo live

Il s'avère étonnamment facile d'ajouter une méthode assertNotRaises à unittest.TestCase (il m'a fallu environ quatre fois plus de temps pour écrire cette réponse que pour le code). Voici une démonstration en direct de la méthode assertNotRaises en action . Juste comme assertRaises , vous pouvez soit passer un callable et argumenter à assertNotRaises, ou vous pouvez l’utiliser dans une instruction with. La démonstration en direct inclut un scénario de test démontrant que assertNotRaises fonctionne comme prévu.

Détails

L'implémentation de assertRaises dans unittest est assez compliquée, mais avec un peu de sous-classement astucieux, vous pouvez remplacer et inverser sa condition d'échec.

assertRaises est une méthode courte qui crée simplement une instance de la classe unittest.case._AssertRaisesContext et la renvoie (voir sa définition dans le module unittest.case). Vous pouvez définir votre propre classe _AssertNotRaisesContext en sous-classant _AssertRaisesContext et en remplaçant sa méthode __exit__:

import traceback
from unittest.case import _AssertRaisesContext

class _AssertNotRaisesContext(_AssertRaisesContext):
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            self.exception = exc_value.with_traceback(None)

            try:
                exc_name = self.expected.__name__
            except AttributeError:
                exc_name = str(self.expected)

            if self.obj_name:
                self._raiseFailure("{} raised by {}".format(exc_name,
                    self.obj_name))
            else:
                self._raiseFailure("{} raised".format(exc_name))

        else:
            traceback.clear_frames(tb)

        return True

Normalement, vous définissez les classes de cas de test en les faisant hériter de TestCase. Si vous héritez d'une sous-classe MyTestCase:

class MyTestCase(unittest.TestCase):
    def assertNotRaises(self, expected_exception, *args, **kwargs):
        context = _AssertNotRaisesContext(expected_exception, self)
        try:
            return context.handle('assertNotRaises', args, kwargs)
        finally:
            context = None

la méthode assertNotRaises sera désormais disponible dans tous vos scénarios de test.

4
tel

Si vous transmettez une classe d'exception à assertRaises(), un gestionnaire de contexte est fourni. Cela peut améliorer la lisibilité de vos tests:

# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
    application = Application("abcdef", "")

Cela vous permet de tester les cas d'erreur dans votre code. 

Dans ce cas, vous testez la PathIsNotAValidOne est déclenchée lorsque vous transmettez des paramètres non valides au constructeur de l'application.

1
hiwaylon

J'ai trouvé utile de corriger la variable unittest comme suit:

def assertMayRaise(self, exception, expr):
  if exception is None:
    try:
      expr()
    except:
      info = sys.exc_info()
      self.fail('%s raised' % repr(info[0]))
  else:
    self.assertRaises(exception, expr)

unittest.TestCase.assertMayRaise = assertMayRaise

Ceci clarifie l’intention lors du test d’absence d’exception:

self.assertMayRaise(None, does_not_raise)

Cela simplifie également les tests en boucle, ce que je me trouve souvent à faire:

# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
  self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
1
AndyJost
def _assertNotRaises(self, exception, obj, attr):                                                                                                                              
     try:                                                                                                                                                                       
         result = getattr(obj, attr)                                                                                                                                            
         if hasattr(result, '__call__'):                                                                                                                                        
             result()                                                                                                                                                           
     except Exception as e:                                                                                                                                                     
         if isinstance(e, exception):                                                                                                                                           
            raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception)) 

pourrait être modifié si vous devez accepter des paramètres.

appeler comme

self._assertNotRaises(IndexError, array, 'sort')
0
znotdead

vous pouvez essayer comme ça. essayer: self.assertRaises (Aucun, fonction, arg1, arg2) sauf: pass si vous ne mettez pas de code dans try à un bloc, il passera à l'exception de 'AssertionError: aucun non levé "et le test sera échoué.

0
lalit