2009-08-25 8 views
2

Comment simuler une entrée utilisateur au milieu d'une fonction appelée par un test unitaire (utilisation de l'unittest de Python 3)? Par exemple, j'ai une fonction foo() dont la sortie est en cours de test. Dans la fonction foo(), il demande l'entrée d'utilisateur:Python 3 unittest simule l'entrée de l'utilisateur

x = input(msg)

Et la sortie est basée sur l'entrée:

print("input: {0}".format(x))

Je voudrais que mon test unitaire pour exécuter foo(), entrez une entrée et comparez le résultat avec le résultat attendu.

Répondre

7

J'ai ce problème régulièrement lorsque j'essaie de tester le code qui affiche des boîtes de dialogue pour la saisie par l'utilisateur, et la même solution devrait fonctionner pour les deux. Vous devez fournir une nouvelle fonction liée au nom input dans votre étendue de test avec la même signature que la fonction standard input qui renvoie juste une valeur de test sans réellement inviter l'utilisateur. Selon la façon dont vos tests et le code sont configurés cette injection peut se faire de plusieurs façons, donc je vais laisser cela comme un exercice pour le lecteur, mais votre méthode de remplacement sera quelque chose de simple comme:

def my_test_input(message): 
    return 7 

Évidemment, vous pouvez également activer le contenu de message si cela était pertinent et renvoyer le type de données de votre choix. Vous pouvez également faire quelque chose de plus souple et général qui permet de réutiliser la même méthode de remplacement dans un certain nombre de situations:

def my_test_input(retval, message): 
    return retval 

et alors vous injecter une fonction partielle dans input:

import functools 
test_input_a = functools.partial(my_test_input, retval=7) 
test_input_b = functools.partial(my_test_input, retval="Foo") 

En quittant test_input_a et test_input_b en tant que fonctions prenant un seul argument message, avec l'argument retval déjà lié.

+0

J'ai fini par faire quelque chose de similaire. J'ai créé une fonction test_input "test_input (msg)" qui remplacerait le comportement par défaut de l'entrée sur le module que je suis en train de tester: "module.input = test_input". Je définis la valeur d'entrée simulée avec une variable globale "sample_input" définie avant la fonction test_input et définie avant chaque test. – royvandewater

2

Avoir des difficultés à tester certains composants en raison de dépendances est généralement un signe de mauvaise conception. Votre fonction foo ne doit pas dépendre de la fonction globale input, mais plutôt d'un paramètre. Ensuite, lorsque vous exécutez le programme dans un environnement de production, vous câblez les choses de telle sorte que le foo est appelé avec le résultat de ce que input renvoie. Donc, foo devrait se lire:

def foo(input): 
    # do something with input 

Cela rendra le test beaucoup plus facile. Et en passant, si vos tests ont des dépendances, ils ne sont plus des tests unitaires, mais plutôt des tests fonctionnels. Jetez un oeil sur Misko Hevery's blog pour plus d'informations sur les tests.

+1

Peut-être, mais * quelque part *, quelqu'un recueille cette entrée.Lorsque vous voulez tester la méthode, vous devez soit recourir à des outils de test fonctionnels qui manipulent une interface utilisateur pour effectuer un test à ce niveau, soit effectuer une injection. Bien sûr, vous devez également effectuer des tests fonctionnels qui manipulent l'interface utilisateur, mais qui doivent être utilisés uniquement pour tester l'interface utilisateur (par exemple, input() prend les données que vous avez fournies) et non les échecs dans les détails d'implémentation non UI. . –

+0

Nick, si le système testé est une application héritée, dans laquelle le refactoring est très dur ou cela prend du temps, mais vous voulez vraiment avoir des tests de caractérisation (qui supporteront réellement le refactoring), alors oui, je '' d utilisez votre méthode. Mais, si l'application est en cours de développement, elle devrait être refactorisée pour que les tests unitaires soient faciles à écrire. –

+0

@ Nick Bastin: "Peut-être, mais quelque part, quelqu'un recueille cette entrée Quand vous voulez tester la méthode en faisant ça ..." Le 'foo (entrée)' le fait. Il n'y a pas "quelque part" d'autre que cela doit être testé. –

Questions connexes