J'utilise pythons mock.patch et j'aimerais changer la valeur de retour pour chaque appel. Voici la mise en garde: la fonction à patcher n'a pas d'entrées, donc je ne peux pas changer la valeur de retour en fonction de l'entrée.
Voici mon code pour référence.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
Mon code de test:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
est juste une version indépendante de la plate-forme (python 2 et 3) de "input". Donc, en fin de compte, j'essaie de se moquer de l'entrée des utilisateurs. J'ai essayé d'utiliser une liste pour la valeur de retour, mais cela ne fonctionne pas.
Vous pouvez voir que si la valeur de retour est quelque chose d'invalide, je vais simplement obtenir une boucle infinie ici. J'ai donc besoin d'un moyen de modifier éventuellement la valeur de retour, de sorte que mon test se termine réellement.
(une autre façon possible de répondre à cette question pourrait être d'expliquer comment je pourrais imiter l'entrée d'utilisateur dans un test unitaire)
Pas un dup de cette question principalement car je n'ai pas la possibilité de faire varier les entrées.
L'un des commentaires de la réponse sur cette question va dans le même sens, mais aucune réponse / commentaire n'a été fourni.
la source
response is not 'y' or 'n' or 'yes' or 'no'
en ne faisant pas ce que vous pensez qu'il fait. Consultez Comment tester une variable par rapport à plusieurs valeurs? et vous ne devez pas utiliseris
pour comparer des valeurs de chaîne, utiliser==
pour comparer des valeurs , pas des identités d'objets.is
pour comparer des chaînes littérales. Ne fais pas ça. Le fait que cela fonctionne (parfois) n'est qu'un détail d'implémentation dans CPython. Aussi,response is not 'y' or 'n' or 'yes' or 'no'
ne fait probablement pas ce que vous pensez que c'est ...Réponses:
Vous pouvez attribuer un itérable à
side_effect
, et la maquette renverra la valeur suivante dans la séquence à chaque fois qu'elle est appelée:Citant la
Mock()
documentation :En aparté, le test
response is not 'y' or 'n' or 'yes' or 'no'
sera pas travailler; vous demandez si l'expression(response is not 'y')
est vraie ou'y'
vraie (toujours le cas, une chaîne non vide est toujours vraie), etc. Les différentes expressions de chaque côté desor
opérateurs sont indépendantes . Consultez Comment tester une variable par rapport à plusieurs valeurs?Vous devriez également pas utiliser
is
pour tester contre une chaîne. L'interpréteur CPython peut réutiliser des objets chaîne dans certaines circonstances , mais ce n'est pas un comportement sur lequel vous devriez compter.En tant que tel, utilisez:
au lieu; cela utilisera des tests d' égalité (
==
) pour déterminer siresponse
référence une chaîne avec le même contenu (valeur).La même chose s'applique à
response == 'y' or 'yes'
; utiliser à laresponse in ('y', 'yes')
place.la source
mock
? Existe-t-il un moyen d'utiliser le patch avec MagicMock comme je le fais avec une maquette standard?Mock
classe stardard .m.side_effect = iter(['foo', 'bar', 'baz'])
).lambda
(une fonction), pas unMagicMock
. Un objet fonction ne peut pas avoir de propriétés, donc l'side_effect
attribut doit être un itérable. Vous ne devriez pas spécifier la méthode comme ça. Meilleure utilisationmock.patch.object(requests.Session, 'post')
; cela aboutit à un objet patcher qui spécifie automatiquement la méthode et qui prend en chargeside_effect
correctement.StopIteration
est déclenché . Vous pouvez utiliser n'importe quel itérateur, donc vous pouvez utiliseritertools.chain(['Foo'], itertools.repeat('Bar'))
pour produireFoo
une fois, puis pour toujours produireBar
.