Como posso ver a saída de impressão normal criada durante a execução do pytest?

401

Às vezes, quero apenas inserir algumas instruções de impressão no meu código e ver o que é impresso quando o exercito. Minha maneira usual de "exercitar" é com os testes pytest existentes. Mas quando eu os executo, não consigo ver nenhuma saída padrão (pelo menos no PyCharm, meu IDE).

Existe uma maneira simples de ver a saída padrão durante uma execução de pytest?

Des
fonte
Somente em caso de falha ou sempre?
17
-s desabilita a captura por teste
hpk42
3
@delnan - Eu gostaria de vê-lo sempre
Des

Respostas:

51

Em um comentário votado para a resposta aceita , Joe pergunta:

Existe alguma maneira de imprimir no console E capturar a saída para que seja exibida no relatório de junção?

No UNIX, isso geralmente é chamado de tweet . Idealmente, fazer xixi em vez de capturar seria o padrão py.test. Não idealmente, nem o py.test nem qualquer plug-in py.test de terceiros existente (... que eu saiba, de qualquer maneira ) são compatíveis com o tee - apesar do Python suportar trivialmente o tee fora da caixa .

O teste de patch de macaco para fazer qualquer coisa sem suporte não é trivial. Por quê? Porque:

  • A maioria das funcionalidades do py.test está bloqueada por trás de um _pytestpacote privado que não se destina a ser importado externamente. Tentar fazer isso sem saber o que você está fazendo normalmente resulta no pytestpacote público gerando exceções obscuras no tempo de execução. Muito obrigado, py.test. Arquitetura realmente robusta que você chegou lá.
  • Mesmo quando você faz descobrir como macaco-patch privado _pytestAPI de uma forma segura, você tem que fazê-lo antes de executar o público pytestrun pacote pelo externo py.testde comando. Você não pode fazer isso em um plug-in (por exemplo, um conftestmódulo de nível superior em seu conjunto de testes). No momento em que o py.test preguiçosamente importa a importação dinâmica do seu plug-in, qualquer classe py.test que você deseja corrigir o patch já foi instanciada - e você não tem acesso a essa instância. Isso implica que, se você deseja que seu patch para macaco seja aplicado de maneira significativa, não poderá mais executar o py.testcomando externo com segurança . Em vez disso, você deve agrupar a execução desse comando com um setuptools personalizadotest comando que (em ordem):
    1. Patches de macaco da _pytestAPI privada .
    2. Chama a pytest.main()função pública para executar o py.testcomando.

Esta resposta corrige py.test -se --capture=noopções para capturar stderr, mas não stdout. Por padrão, essas opções não capturam nem stderr nem stdout. Isso não é nada, é claro. Mas toda grande jornada começa com uma prequela tediosa que todos esquecem em cinco anos.

Por que fazer isso? Agora vou lhe contar. Meu conjunto de testes orientado por py.test contém testes funcionais lentos. A exibição do stdout desses testes é útil e reconfortante, impedindo que o leycec atinja killall -9 py.testquando outro teste funcional de longa duração falha em fazer qualquer coisa por semanas a fio. A exibição do stderr desses testes, no entanto, impede que o py.test relate tracebacks de exceção em falhas de teste. O que é completamente inútil. Portanto, coagimos py.test para capturar stderr, mas não stdout.

Antes de chegarmos a isso, esta resposta supõe que você já tenha um testcomando setuptools personalizado invocando py.test. Caso contrário, consulte a subseção Integração manual da página bem escrita de Boas Práticas do py.test .

Você não instalar pytest-runner , um terceiro setuptools do plugin fornecendo um setuptools personalizados testtambém comandam invocando py.test. Se o pytest-runner já estiver instalado, você provavelmente precisará desinstalar esse pacote pip3 e adotar a abordagem manual vinculada a acima.

Supondo que você seguiu as instruções em Integração manual destacadas acima, sua base de código agora deve conter um PyTest.run_tests()método. Modifique este método para se parecer com:

class PyTest(TestCommand):
             .
             .
             .
    def run_tests(self):
        # Import the public "pytest" package *BEFORE* the private "_pytest"
        # package. While importation order is typically ignorable, imports can
        # technically have side effects. Tragicomically, that is the case here.
        # Importing the public "pytest" package establishes runtime
        # configuration required by submodules of the private "_pytest" package.
        # The former *MUST* always be imported before the latter. Failing to do
        # so raises obtuse exceptions at runtime... which is bad.
        import pytest
        from _pytest.capture import CaptureManager, FDCapture, MultiCapture

        # If the private method to be monkey-patched no longer exists, py.test
        # is either broken or unsupported. In either case, raise an exception.
        if not hasattr(CaptureManager, '_getcapture'):
            from distutils.errors import DistutilsClassError
            raise DistutilsClassError(
                'Class "pytest.capture.CaptureManager" method _getcapture() '
                'not found. The current version of py.test is either '
                'broken (unlikely) or unsupported (likely).'
            )

        # Old method to be monkey-patched.
        _getcapture_old = CaptureManager._getcapture

        # New method applying this monkey-patch. Note the use of:
        #
        # * "out=False", *NOT* capturing stdout.
        # * "err=True", capturing stderr.
        def _getcapture_new(self, method):
            if method == "no":
                return MultiCapture(
                    out=False, err=True, in_=False, Capture=FDCapture)
            else:
                return _getcapture_old(self, method)

        # Replace the old with the new method.
        CaptureManager._getcapture = _getcapture_new

        # Run py.test with all passed arguments.
        errno = pytest.main(self.pytest_args)
        sys.exit(errno)

Para ativar esse patch de macaco, execute py.test da seguinte maneira:

python setup.py test -a "-s"

Stderr, mas não stdout, agora serão capturados. Bacana!

Estender o patch de macaco acima para tee stdout e stderr é deixado como um exercício para o leitor com um barril cheio de tempo livre.

Cecil Curry
fonte
33

Ao executar o teste, use a -sopção Todas as instruções de impressão exampletest.pyserão impressas no console quando o teste for executado.

py.test exampletest.py -s
Diversão de verão
fonte
31

De acordo com a documentação do pytest , a versão 3 do pytest pode desativar temporariamente a captura em um teste:

def test_disabling_capturing(capsys):
    print('this output is captured')
    with capsys.disabled():
        print('output not captured, going directly to sys.stdout')
    print('this output is also captured')
Roman Susi
fonte
20

O pytest captura o stdout de testes individuais e os exibe apenas em determinadas condições, junto com o resumo dos testes que ele imprime por padrão.

Informações de resumo extras podem ser exibidas usando a opção '-r':

pytest -rP

mostra a saída capturada dos testes aprovados.

pytest -rx

mostra a saída capturada de testes com falha (comportamento padrão).

A formatação da saída é mais bonita com -r do que com -s.

Sunthar
fonte
2
Esta é a resposta real que eu estava procurando! Obrigado. (Ter a saída padrão vir APÓS os resultados do teste é desejado Quando eles estão intercalados, as linhas impressas perder valor..)
bossylobster
18

Tente pytest -s -v test_login.pyobter mais informações no console.

-v é um curto --verbose

-s significa 'desativar todas as capturas'



Alex Makarenko
fonte
11
se você estiver usando o arquivo pytest.ini, poderá usar: addopts = -s -v python_files = test_login.py
timj98 15/18
4

Se você estiver usando o PyCharm IDE, poderá executar esse teste individual ou todos os testes usando a barra de ferramentas Executar. A janela da ferramenta Executar exibe a saída gerada pelo seu aplicativo e você pode ver todas as instruções de impressão como parte da saída de teste.

Gemini Jain
fonte
Você sabe como imprimir o PyCharm enquanto o teste está em execução? (em vez de depois que o teste passou)
Alexandre Huat
3

pytest --capture=tee-sysfoi adicionado recentemente. Você pode capturar e ver a saída em stdout / err.

meonstackexchange
fonte
-4

As outras respostas não funcionam. A única maneira de ver a saída capturada é usando o seguinte sinalizador:

pytest --show-capture all

aaa90210
fonte
6
--show-capture=allé o valor padrão. Adicioná-lo não afeta nada.
hoefling