2009-10-18 7 views
1

J'ai une classe comme les suivantes:Unité testant une méthode appelée lors de l'initialisation?

class Positive(object): 
    def __init__(self, item): 
     self._validate_item(item) 
     self.item = item 

    def _validate_item(self, item): 
     if item <= 0: 
      raise ValueError("item should be positive.") 

Je voudrais écrire un test unitaire pour _validate_item(), comme ce qui suit:

class PositiveTests(unittest.TestCase): 
    def test_validate_item_error(self): 
     self.assertRaises(
      ValueError, 
      Positive._validate_item, 
      0 
     ) 

Malheureusement, cela ne fonctionnera pas parce que l'unité test ne passe que 0 à la méthode, au lieu d'une instance de classe (pour le paramètre self) et le 0. Existe-t-il une autre solution que de devoir tester cette méthode de validation indirectement via le __init__() de la classe?

Répondre

7

Si vous n'êtes pas en utilisant l'auto dans le corps de la méthode, il est une indication qu'il pourrait ne pas besoin d'être un membre de la classe. Vous pouvez déplacer la fonction _validate_item dans le périmètre du module:

def _validate_item(item): 
    if item <= 0: 
     raise ValueError("item should be positive.") 

Ou si elle a vraiment de rester dans la classe, la marque la méthode statique:

class Positive(object): 
    def __init__(self, item): 
     self._validate_item(item) 
     self.item = item 

    @staticmethod 
    def _validate_item(item): 
     if item <= 0: 
      raise ValueError("item should be positive.") 

Votre test doit alors travailler comme écrit.

+0

J'aime cette réponse. Si vous ressentez le besoin d'écrire des tests pour _validate_item() par lui-même, il est probable qu'il appartienne à lui-même. –

+0

staticmethods sont pour la plupart inutiles en Python, dans ce cas utilisez un classmethod! – u0b34a0f6ae

+0

Je n'utiliserais pas le décorateur '@ classmethod' ici pour la même raison que je ne le définirais pas comme une méthode d'instance. Il n'y a pas d'utilisation de 'cls'. Compte tenu de mes compétences, je ferais une fonction privée à la portée du module. –

1

Vous ne créez pas une instance de Positive. Que diriez-vous

Positive()._validate_item, 0 
+0

Ce code déclenche une erreur TypeError car 'Positive .__ init __()' manque l'argument 'item'. –

+0

Cela vous montre que vous essayez de tester l'implémentation "_validate_item", pas l'interface. Je pense que tester 'Positive (0) 'est * beaucoup * meilleur que tester' _validate_item (0)'. – u0b34a0f6ae

+0

Le commentaire ci-dessus est @gotgenes – u0b34a0f6ae

1

Eh bien, _validate_item() est testé par le constructeur. L'appeler avec une valeur nulle ou négative augmentera l'exception ValueError.

Prendre du recul, c'est l'objectif non? La "condition" est que l'objet ne doit pas être créé avec une valeur nulle ou négative.

Maintenant, il s'agit d'un exemple artificiel, donc ce qui précède ne pouvait pas être applicable à la classe réelle; une autre possibilité, pour avoir vraiment un test dédié à la méthode _validate_item(), pourrait être de créer un objet avec une valeur positive, puis d'appeler le validate_item() dessus.

Questions connexes