Comment imprimer sur console dans pytest?

175

J'essaye d'utiliser TDD (développement piloté par les tests) avec pytest. pytestne sera pas printà la console lorsque je l'utilise print.

J'utilise pytest my_tests.pypour l'exécuter.

Le documentationsemble dire que cela devrait fonctionner par défaut: http://pytest.org/latest/capture.html

Mais:

import myapplication as tum

class TestBlogger:

    @classmethod
    def setup_class(self):
        self.user = "alice"
        self.b = tum.Blogger(self.user)
        print "This should be printed, but it won't be!"

    def test_inherit(self):
        assert issubclass(tum.Blogger, tum.Site)
        links = self.b.get_links(posts)
        print len(links)   # This won't print either.

Rien n'est imprimé sur ma console de sortie standard (juste la progression normale et le nombre de tests réussis / échoués).

Et le script que je teste contient print:

class Blogger(Site):
    get_links(self, posts):
        print len(posts)   # It won't get printed in the test.

Dans le unittestmodule, tout est imprimé par défaut, ce qui est exactement ce dont j'ai besoin. Cependant, je souhaite utiliser pytestpour d'autres raisons.

Quelqu'un sait-il comment afficher les instructions d'impression?

BBModifier
la source
1
Peut-être que stdout est en cours d'écrasement. Que se passe-t-il si vous utilisez sys.stdout.write("Test")? Et pourquoi pas sys.__stdout__.write("Test")? Ce dernier devrait toujours écrire dans la sortie standard définie par le système, qui devrait être la console. Si les deux commandes font des choses différentes, alors stdout est modifié; s'ils font la même chose, alors le problème est autre chose.
TheSoundDefense

Réponses:

205

Par défaut, py.testcapture le résultat de la sortie standard afin qu'il puisse contrôler la façon dont il l'imprime. S'il ne le faisait pas, il vomirait beaucoup de texte sans le contexte de quel test imprimait ce texte.

Cependant, si un test échoue, il inclura une section dans le rapport résultant qui montre ce qui a été imprimé selon la norme dans ce test particulier.

Par exemple,

def test_good():
    for i in range(1000):
        print(i)

def test_bad():
    print('this should fail!')
    assert False

Résultats dans la sortie suivante:

>>> py.test tmp.py
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py .F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
------------------------------- Captured stdout --------------------------------
this should fail!
====================== 1 failed, 1 passed in 0.04 seconds ======================

Notez la Captured stdoutsection.

Si vous souhaitez voir les printinstructions lors de leur exécution, vous pouvez passer l' -sindicateur à py.test. Cependant, notez que cela peut parfois être difficile à analyser.

>>> py.test tmp.py -s
============================= test session starts ==============================
platform darwin -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
plugins: cache, cov, pep8, xdist
collected 2 items

tmp.py 0
1
2
3
... and so on ...
997
998
999
.this should fail!
F

=================================== FAILURES ===================================
___________________________________ test_bad ___________________________________

    def test_bad():
        print('this should fail!')
>       assert False
E       assert False

tmp.py:7: AssertionError
====================== 1 failed, 1 passed in 0.02 seconds ======================
Tbekolay
la source
2
Éminemment pratique. Bon travail!
cmc
1
hmm ... ne consigne toujours pas mes déclarations imprimées
Tim Boland le
68

L'utilisation de l' -soption imprimera la sortie de toutes les fonctions, ce qui peut être trop.

Si vous avez besoin d'une sortie particulière, la page de documentation que vous avez mentionnée propose quelques suggestions:

  1. Insérez assert False, "dumb assert to make PyTest print my stuff"à la fin de votre fonction, et vous verrez votre sortie en raison d'un test échoué.

  2. Vous avez un objet spécial qui vous est passé par PyTest, et vous pouvez écrire la sortie dans un fichier pour l'inspecter plus tard, comme

    def test_good1(capsys):
        for i in range(5):
            print i
        out, err = capsys.readouterr()
        open("err.txt", "w").write(err)
        open("out.txt", "w").write(out)

    Vous pouvez ouvrir les fichiers outet errdans un onglet séparé et laisser l'éditeur l'actualiser automatiquement pour vous, ou py.test; cat out.txtexécuter une simple commande shell pour exécuter votre test.

C'est une façon plutôt hackeuse de faire des choses, mais c'est peut-être ce dont vous avez besoin: après tout, TDD signifie que vous vous embêtez et que vous le laissez propre et silencieux quand il est prêt :-).

dmitry_romanov
la source
J'ai essayé la version 1. avec pytest 3.8.1, malheureusement, il n'imprime que le bloc de fonction de test, mais pas la sortie des instructions d'impression: (plus d'astuces pour cela?
UV
@UV - Au lieu d'utiliser la print()fonction, vous devez mettre la variable ou le message que vous souhaitez imprimer après la virgule dans l'instruction assert. Par exemple assert False, what_are_you, «imprimera» la valeur de what_are_youdans le rapport pytest.
Mart Van de Ven
43

Réponse courte

Utilisez l' -soption:

pytest -s

Réponse détaillée

À partir de la documentation :

Pendant l'exécution du test, toute sortie envoyée à stdout et stderr est capturée. Si un test ou une méthode de configuration échoue, sa sortie capturée correspondante sera généralement affichée avec le suivi de l'échec.

pytesta l'option --capture=methoddans laquelle methodest par test méthode de capture, et pourrait être l' une des suivantes: fd, sysou no. pytesta également l'option -squi est un raccourci pour --capture=no, et c'est l'option qui vous permettra de voir vos instructions d'impression dans la console.

pytest --capture=no     # show print statements in console
pytest -s               # equivalent to previous command

Définition des méthodes de capture ou désactivation de la capture

Il existe deux manières d' pytesteffectuer la capture:

  1. capture de niveau descripteur de fichier (FD) (par défaut): toutes les écritures aller au fichier du système d'exploitation descripteurs 1 et 2 sera capturé.

  2. Capture au niveau sys : Seules les écritures dans les fichiers Python sys.stdout et sys.stderr seront capturées. Aucune capture d'écritures sur les descripteurs de fichiers n'est effectuée.

pytest -s            # disable all capturing
pytest --capture=sys # replace sys.stdout/stderr with in-mem files
pytest --capture=fd  # also point filedescriptors 1 and 2 to temp file
lmiguelvargasf
la source
17

Je avais besoin d'imprimer Avertissement important sur les tests sautées exactement quand PyTestcoupé littéralement tout .

Je ne voulais pas échouer un test pour envoyer un signal, alors j'ai fait un hack comme suit:

def test_2_YellAboutBrokenAndMutedTests():
    import atexit
    def report():
        print C_patch.tidy_text("""
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.""")
    if sys.stdout != sys.__stdout__:
        atexit.register(report)

Le atexitmodule me permet d'imprimer des trucs après avoir PyTest publié les flux de sortie. La sortie ressemble à ceci:

============================= test session starts ==============================
platform linux2 -- Python 2.7.3, pytest-2.9.2, py-1.4.31, pluggy-0.3.1
rootdir: /media/Storage/henaro/smyth/Alchemist2-git/sources/C_patch, inifile: 
collected 15 items 

test_C_patch.py .....ssss....s.

===================== 10 passed, 5 skipped in 0.15 seconds =====================
In silent mode PyTest breaks low level stream structure I work with, so
I cannot test if my functionality work fine. I skipped corresponding tests.
Run `py.test -s` to make sure everything is tested.
~/.../sources/C_patch$

Le message est imprimé même PyTesten mode silencieux, et n'est pas imprimé si vous exécutez des trucs avec py.test -s, donc tout est déjà bien testé.

dmitry_romanov
la source
1
Parfait pour générer des métriques de test personnalisées.
z0r
5

Selon la documentation pytest , pytest --capture=sysdevrait fonctionner. Si vous souhaitez capturer le standard à l'intérieur d'un test, reportez-vous à l'appareil capsys.

Karthik Gomadam Rajagopal
la source
Cela fonctionne pour moi quand j'ai besoin d'une variable d'impression dans le terminal ...
Sukma Saputra
2

À l'origine, je suis venu ici pour trouver comment PyTestimprimer dans la console de VSCode tout en exécutant / déboguant le test unitaire à partir de là. Cela peut être fait avec la launch.jsonconfiguration suivante . Compte tenu .venvdu dossier de l'environnement virtuel.

    "version": "0.2.0",
    "configurations": [
        {
            "name": "PyTest",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "module": "pytest",
            "args": [
                "-sv"
            ],
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.venv",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }
    ]
}
dummyDev
la source