J'écris des tests pour une fonction comme la suivante:
def foo():
print 'hello world!'
Donc, quand je veux tester cette fonction, le code sera comme ceci:
import sys
from foomodule import foo
def test_foo():
foo()
output = sys.stdout.getline().strip() # because stdout is an StringIO instance
assert output == 'hello world!'
Mais si j'exécute nosetests avec le paramètre -s, le test plante. Comment puis-je capturer la sortie avec unittest ou un module nasal?
python
unit-testing
nosetests
python-nose
Pedro Valence
la source
la source
with mock.patch('sys.stdout', new_callable=StringIO.StringIO):
pypi.python.org/pypi/mockRéponses:
J'utilise ce gestionnaire de contexte pour capturer la sortie. Il utilise finalement la même technique que certaines des autres réponses en les remplaçant temporairement
sys.stdout
. Je préfère le gestionnaire de contexte car il englobe toute la comptabilité dans une seule fonction, donc je n'ai pas à réécrire de code d'essai, et je n'ai pas à écrire des fonctions de configuration et de démontage juste pour cela.Utilisez-le comme ceci:
De plus, comme l'état de sortie d'origine est restauré à la sortie du
with
bloc, nous pouvons configurer un deuxième bloc de capture dans la même fonction que le premier, ce qui n'est pas possible en utilisant les fonctions de configuration et de démontage, et devient verbeux lors de l'écriture try-finally bloque manuellement. Cette capacité était utile lorsque l'objectif d'un test était de comparer les résultats de deux fonctions l'une par rapport à l'autre plutôt qu'avec une valeur précalculée.la source
TypeError: unicode argument expected, got 'str'
(le type passé à imprimer (str / unicode) n'est pas pertinent).from io import BytesIO as StringIO
et en python 3 justefrom io import StringIO
. Semblait résoudre le problème dans mes tests, je pense.strip()
auunicode
retour deStringIO.getvalue()
?sys
. Avec votre instruction d'importation, vous créez une variable locale nomméestderr
qui a reçu une copie de la valeur danssys.stderr
. Les modifications apportées à l'un ne sont pas reflétées dans l'autre.Si vous voulez vraiment faire cela, vous pouvez réaffecter sys.stdout pour la durée du test.
Si j'écrivais ce code, cependant, je préférerais passer un
out
paramètre facultatif à lafoo
fonction.Ensuite, le test est beaucoup plus simple:
la source
StringIO
classe doit maintenant être importée duio
module.from io import StringIO
fonctionne en python 2.6+.from io import StringIO
en python 2, vous obtenez unTypeError: unicode argument expected, got 'str'
lors de l'impression.with redirect_stdout(out):
saved_stdout = sys.stdout
, vous avez toujours une référence magique à celasys.__stdout__
, par exemple, vous n'en avez besoin quesys.stdout = sys.__stdout__
dans votre nettoyage.Depuis la version 2.7, vous n'avez plus besoin de réassigner
sys.stdout
, cela est fourni viabuffer
flag . De plus, c'est le comportement par défaut de nosetest.Voici un exemple d'échec dans un contexte non tamponné:
Vous pouvez définir par buffer
unit2
indicateur de ligne de commande-b
,--buffer
ou dans lesunittest.main
options. Le contraire est obtenu grâce aunosetest
drapeau--nocapture
.la source
--nocapture
; en particulier, si cet indicateur est défini, le mode tampon sera désactivé. Vous avez donc la possibilité soit de voir la sortie sur le terminal, soit de pouvoir tester que la sortie est comme prévu.Beaucoup de ces réponses ont échoué pour moi parce que vous ne pouvez pas
from StringIO import StringIO
en Python 3. Voici un extrait de code de travail minimum basé sur le commentaire de @ naxa et le livre de recettes Python.la source
En python 3.5, vous pouvez utiliser
contextlib.redirect_stdout()
etStringIO()
. Voici la modification de votre codela source
redirect_stdout()
etredirect_stderr()
renvoyer leur argument d'entrée. Donc,with contextlib.redirect_stdout(StringIO()) as temp_stdout:
vous donne tout en une seule ligne. Testé avec 3.7.1.J'apprends juste Python et je me suis retrouvé aux prises avec un problème similaire à celui ci-dessus avec des tests unitaires pour les méthodes avec sortie. Mon test unitaire de réussite pour le module foo ci-dessus a fini par ressembler à ceci:
la source
sys.stdout.getvalue().strip()
comparaison et ne pas tricher avec\n
:)from io import StringIO
L'écriture de tests nous montre souvent une meilleure façon d'écrire notre code. Semblable à la réponse de Shane, j'aimerais suggérer une autre façon de voir cela. Voulez-vous vraiment affirmer que votre programme a produit une certaine chaîne, ou simplement qu'il a construit une certaine chaîne pour la sortie? Cela devient plus facile à tester, car nous pouvons probablement supposer que l'
print
instruction Python fait correctement son travail.Ensuite, votre test est très simple:
Bien sûr, si vous avez vraiment besoin de tester la sortie réelle de votre programme, n'hésitez pas à ne pas en tenir compte. :)
la source
foo()
cela ne fait rien d'autre que d'appeler l'instruction print, ce n'est probablement pas un problème.Sur la base de la réponse de Rob Kennedy, j'ai écrit une version basée sur les classes du gestionnaire de contexte pour tamponner la sortie.
L'utilisation est comme:
Voici la mise en œuvre:
la source
Ou pensez à l'utiliser
pytest
, il a un support intégré pour l'affirmation de stdout et stderr. Voir la documentationla source
Les deux n611x007 et Noumenon déjà suggéré d' utiliser
unittest.mock
, mais cette réponse adapte Acumenus de montrer comment vous pouvez facilement envelopper desunittest.TestCase
méthodes pour interagir avec un moquéstdout
.la source
En m'appuyant sur toutes les réponses impressionnantes de ce fil, voici comment je l'ai résolu. Je voulais le garder aussi stock que possible. J'ai augmenté le mécanisme de test unitaire en utilisant
setUp()
pour capturersys.stdout
etsys.stderr
ajouté de nouvelles API d'assert pour vérifier les valeurs capturées par rapport à une valeur attendue, puis restaurersys.stdout
etsys.stderr
surtearDown(). I did this to keep a similar unit test API as the built-in
unittestAPI while still being able to unit test values printed to
sys.stdoutor
sys.stderr`.Lorsque le test unitaire est exécuté, la sortie est:
la source