72 votes

Objet Python Mock avec méthode appelée plusieurs fois

J'ai une classe que je me suis mise à l'essai qui a une dépendance à une autre classe (un exemple de ce qui est transmis à la COUPE de la méthode init). Je veux, à se moquer de cette classe à l'aide de Python se Moquer de la bibliothèque.

Ce que j'ai, c'est quelque chose comme:

mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.return_value = "the value I want the mock to return"
assertTrue(mockobj.methodfromdepclass(42), "the value I want the mock to return")

cutobj = ClassUnderTest(mockobj)

Ce qui est bien, mais "methodfromdepclass" est paramétrée méthode, et comme tel, je veux créer un seul objet fantaisie, où selon ce que les arguments sont passés à methodfromdepclass il renvoie des valeurs différentes.

La raison, je veux que ce comportement paramétré est que je veux créer plusieurs instances de ClassUnderTest qui contiennent des valeurs différentes (dont les valeurs sont produites par ce qui est retourné à partir de la mockobj).

Un peu ce que je pense (bien sûr, cela ne fonctionne pas):

mockobj = Mock(spec=MyDependencyClass)
mockobj.methodfromdepclass.ifcalledwith(42).return_value = "you called me with arg 42"
mockobj.methodfromdepclass.ifcalledwith(99).return_value = "you called me with arg 99"

assertTrue(mockobj.methodfromdepclass(42), "you called me with arg 42")
assertTrue(mockobj.methodfromdepclass(99), "you called me with arg 99")

cutinst1 = ClassUnderTest(mockobj, 42)
cutinst2 = ClassUnderTest(mockobj, 99)

# now cutinst1 & cutinst2 contain different values

Comment puis-je réaliser cette "ifcalledwith" genre " de la sémantique?

97voto

k.parnell Points 764

Essayez side_effect

 def my_side_effect(*args, **kwargs):
    if args[0] == 42:
        return "Called with 42"
    elif args[0] == 43:
        return "Called with 43"
    elif kwarg['foo'] == 7:
        return "Foo is seven"

mockobj.mockmethod.side_effect = my_side_effect
 

61voto

abourget Points 756

Un peu plus doux:

 mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}[x]
 

ou pour plusieurs arguments:

 mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}[x]
 

ou avec une valeur par défaut:

 mockobj.method.side_effect = lambda x: {123: 100, 234: 10000}.get(x, 20000)
 

ou une combinaison des deux:

 mockobj.method.side_effect = lambda *x: {(123, 234): 100, (234, 345): 10000}.get(x, 20000)
 

et joyeusement en haut nous allons.

11voto

Addison Points 160

Je suis tombé sur cela lorsque je faisais mes propres tests. Si vous ne vous souciez pas de capturer des appels à votre methodfromdepclass () mais que vous en avez juste besoin pour retourner quelque chose, alors ce qui suit peut suffire:

 def makeFakeMethod(mapping={}):
    def fakeMethod(inputParam):
        return mapping[inputParam] if inputParam in mapping else None
    return fakeMethod

mapping = {42:"Called with 42", 59:"Called with 59"}
mockobj.methodfromdepclass = makeFakeMethod(mapping)
 

Voici une version paramétrée:

 def makeFakeMethod():
    def fakeMethod(param):
        return "Called with " + str(param)
    return fakeMethod
 

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