web-dev-qa-db-fra.com

Python fausse plusieurs valeurs de retour

J'utilise pythons mock.patch et souhaite modifier la valeur de retour pour chaque appel. Voici l'avertissement: la fonction en cours de correction 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 n'est qu'une version de "input" indépendante de la plate-forme (python 2 et 3). Donc, en fin de compte, j'essaie de simuler les commentaires des utilisateurs. J'ai essayé d'utiliser une liste pour la valeur de retour, mais cela ne semble pas fonctionner.

Vous pouvez voir que si la valeur de retour est quelque chose d'invalide, je vais simplement obtenir une boucle infinie ici. Il me faut donc un moyen de changer éventuellement la valeur de retour pour que mon test se termine réellement.

(Une autre façon de répondre à cette question pourrait être d'expliquer comment je pourrais imiter la saisie de l'utilisateur dans un test unitaire)


Pas un dup de cette question principalement parce que je n'ai pas la capacité 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.

120
Nick Humrich

Vous pouvez affecter un itérable à side_effect, et le simulacre renverra la valeur suivante de la séquence à chaque appel:

>>> from unittest.mock import Mock
>>> m = Mock()
>>> m.side_effect = ['foo', 'bar', 'baz']
>>> m()
'foo'
>>> m()
'bar'
>>> m()
'baz'

Citant la documentation Mock()) :

Si side_effect est une variable, chaque appel à la simulation renvoie la valeur suivante de la variable.

En passant, le test response is not 'y' or 'n' or 'yes' or 'no' ne fonctionnera pas ; vous demandez si l'expression (response is not 'y') est vraie ou 'y' est vraie (toujours le cas, une chaîne non vide est toujours vraie), etc. Les différentes expressions de part et d'autre de or les opérateurs sont indépendants . Voir Comment tester une variable contre plusieurs valeurs?

Vous devriez également ne pas utiliser is pour tester 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.

A ce titre, utilisez:

response not in ('y', 'n', 'yes', 'no')

au lieu; ceci utilisera des tests d'égalité (==) pour déterminer si response référence une chaîne avec le même contenu (valeur).

La même chose s'applique à response == 'y' or 'yes'; utilisez response in ('y', 'yes') à la place.

231
Martijn Pieters