Como imprimir no console em pytest?


175

Estou tentando usar TDD (desenvolvimento orientado a teste) com pytest. pytestnão vai printpara o console quando eu uso print.

Estou usando pytest my_tests.pypara executá-lo.

O documentationparece dizer que ele deve funcionar por padrão: http://pytest.org/latest/capture.html

Mas:

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.

Nada é impresso no meu console de saída padrão (apenas o progresso normal e quantos testes foram aprovados / reprovados).

E o script que estou testando contém print:

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

No unittestmódulo, tudo é impresso por padrão, que é exatamente o que eu preciso. No entanto, desejo usar pytestpor outros motivos.

Alguém sabe como fazer com que as instruções de impressão sejam exibidas?


1
Talvez stdout esteja sendo substituído. O que acontece se você usar sys.stdout.write("Test")? Que tal sys.__stdout__.write("Test")? O último deve sempre gravar no stdout definido pelo sistema, que deve ser o console. Se os dois comandos fazem coisas diferentes, o stdout está sendo alterado; se eles fazem a mesma coisa, então o problema é outra coisa.
TheSoundDefense 7/07

Respostas:


205

Por padrão, py.testcaptura o resultado da saída padrão para poder controlar como a imprime. Se isso não acontecesse, seria possível enviar muito texto sem o contexto de qual teste imprimia esse texto.

No entanto, se um teste falhar, incluirá uma seção no relatório resultante que mostra o que foi impresso com o padrão nesse teste específico.

Por exemplo,

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

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

Resultados na seguinte saída:

>>> 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 ======================

Observe a Captured stdoutseção.

Se você deseja ver as printinstruções como elas são executadas, pode passar a -sflag para py.test. No entanto, observe que isso às vezes pode ser difícil de analisar.

>>> 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 ======================

2
Eminentemente prático. Bom trabalho!
Cmc

1
hmm ... ainda não registra minhas declarações de impressão
Tim Boland

67

Usar a -sopção imprimirá a saída de todas as funções, que podem ser demais.

Se você precisar de uma saída específica, a página do documento que você mencionou oferece algumas sugestões:

  1. Insira assert False, "dumb assert to make PyTest print my stuff"no final de sua função, e você verá sua saída devido a falha no teste.

  2. Você tem um objeto especial passado pelo PyTest e pode gravar a saída em um arquivo para inspecioná-lo mais tarde, como

    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)

    Você pode abrir os arquivos oute errem uma guia separada e deixar o editor atualizá-lo automaticamente para você ou py.test; cat out.txtexecutar um simples comando shell para executar seu teste.

Essa é uma maneira bastante tola de fazer coisas, mas pode ser que você precise: afinal, TDD significa que você mexe com as coisas e deixa tudo limpo e silencioso quando estiver pronto :-).


i tentou versão 1. com pytest 3.8.1, infelizmente, só imprime o bloco de função de teste, mas não a saída de instruções de impressão :( mais nenhum truques para isso?
UV

@UV - Em vez de usar a print()função, você deve colocar a variável ou mensagem que deseja imprimir após a vírgula na declaração assert. Por exemplo assert False, what_are_you, 'imprimirá' o valor de what_are_youno relatório pytest.
Mart Van de Ven

43

Resposta curta

Use a -sopção:

pytest -s

Resposta detalhada

Dos documentos :

Durante a execução do teste, qualquer saída enviada para stdout e stderr é capturada. Se um teste ou um método de instalação falhar, a saída capturada de acordo geralmente será mostrada junto com o rastreamento de falha.

pytesttem a opção --capture=methodna qual methodé por teste método de captura, e pode ser um dos seguintes: fd, sysou no. pytesttambém tem a opção -sque é um atalho --capture=no, e essa é a opção que permitirá que você veja suas instruções de impressão no console.

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

Configurando métodos de captura ou desativando a captura

Existem duas maneiras pelas quais a pytestcaptura pode ser realizada:

  1. captura no nível do descritor de arquivo (FD) (padrão): todas as gravações enviadas para os descritores de arquivo 1 e 2 do sistema operacional serão capturadas.

  2. Captura no nível do sys : somente gravações nos arquivos Python sys.stdout e sys.stderr serão capturadas. Nenhuma captura de gravações em filedescriptors é executada.

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

17

Eu precisava imprimir um aviso importante sobre testes ignorados exatamente quando PyTestsilenciosamente literalmente tudo .

Como não queria falhar em um teste para enviar um sinal, fiz um hack da seguinte maneira:

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)

O atexitmódulo permite que eu imprima coisas após PyTest liberar os fluxos de saída. A saída é a seguinte:

============================= 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$

A mensagem é impressa mesmo quando PyTestestá no modo silencioso e não é impressa se você executar coisas py.test -s, portanto tudo já foi testado com bom gosto.


1
Perfeito para gerar métricas de teste personalizadas.
z0r 16/01


2

Originalmente, vim aqui para descobrir como PyTestimprimir no console do VSCode durante a execução / depuração do teste de unidade a partir daí. Isso pode ser feito com a seguinte launch.jsonconfiguração. Dada .venva pasta do ambiente virtual.

    "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"
            ]
        }
    ]
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.