2017-09-19 3 views
0

J'utilise unittest.mock, cette merveilleuse bibliothèque. Cependant, j'ai été surpris par un comportement inattendu, et je ne vois pas une solution évidente. Je l'utilise pour mes tests unitaires et il est essentiel de comprendre parfaitement comment il se comporte pour avoir des tests utiles.Comment tester si la méthode de l'instance est appelée avec "self" en se moquant?

Je sais que le code ci-dessous dans show_bar est cassé, il appelle un classmethod au lieu de la méthode d'instance. Cependant, tous mes mockunittests passent:

code contenant un bug:

class Foo(object): 
    def bar(self): 
     return "bar" 

    def show_bar(self): 
     return Foo.bar() 

utilisation prévue:

foo = Foo() 
assert foo.show_bar() == "bar" 
# => throw exception: bar() missing 1 required positional argument: 'self' 

UnitTest tente en vain de rattraper cette erreur avec mock:

from unittest.mock import patch 
with patch.object(Foo, 'bar', return_value="bar") as mock: 
    foo = Foo() 
    assert foo.show_bar() == "bar" 
mock.assert_called_once() 
# => no errors 

Idéalement, je voudrais affirmer que bar est appelée avec self.bar() et NON Foo.bar(); ce qui est faux. Malheureusement, en utilisant mock.assert_called_with() ne prend pas en compte le paramètre self ni cls, donc je suis un peu confus.

EDIT: Essayer de clarifier. Je suis à la recherche de bonnes pratiques pour utiliser la bibliothèque unittest.mock lorsque nous avons besoin de patcher la méthode d'un objet. Il ne semble pas clair pour moi comment le patcher, actuellement je n'ai aucun moyen d'affirmer si elle appelle self.bar ou Foo.bar.

+0

ne vous moquez pas quoi que ce soit, il suffit d'appeler 'f = Foo(); f.bar() 'dans votre code de test. Avec l'implémentation interrompue, cela déclenchera un 'TypeError', ce qui fera échouer le test. –

+0

Aussi et FWIW, cela n'a rien à voir avec 'classmethod' - dans votre exemple' Foo.bar' est une méthode d'instance indépendante. –

+0

Désolé, le code est trop simplifié et j'ai * besoin * d'utiliser le mock car le code réel de la méthode n'est pas callable sans se moquer de sa valeur de retour. De plus, quand le développeur 'show_bar' appelle' Foo.bar() ', je supposais que' Foo.bar' est soit une méthode de classe, soit une méthode static. Cela semble une déclaration raisonnable? – Doomsday

Répondre

1

Je ne comprends pas vraiment pourquoi vous auriez besoin de se moquer de la méthode pour tester qu'elle ne déclenche pas une erreur TypeError lorsqu'elle est appelée, mais de toute façon ... Quelqu'un d'autre pourrait expliquer comment résoudre cela en utilisant unittest.mock peut sauter juste unittest.mock et Foo.bar maquette par vous-même:

callargs = dict() 
def mock_bar(self): 
    callargs["self"] = self 
    return "bar" 

foobar = Foo.__dict__["bar"] 
Foo.bar = mock_bar 
try: 
    foo = Foo() 
    assert foo.show_bar() == "bar" 
    assert "self" in callargs 
    assert callargs["self"] is foo 
finally: 
    Foo.bar = foobar 
+0

En fait, je n'essaie pas de résoudre mon problème qui est trivial, ni moqueur "manuellement" ma classe, je cherche seulement à utiliser 'unittest.mock' correctement pour remplacer les appels de méthodes en unittesting le contexte. Merci d'avoir essayé d'aider quand même! – Doomsday