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
_pytest
pacote privado que não se destina a ser importado externamente. Tentar fazer isso sem saber o que você está fazendo normalmente resulta no pytest
pacote 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
_pytest
API de uma forma segura, você tem que fazê-lo antes de executar o público pytest
run pacote pelo externo py.test
de comando. Você não pode fazer isso em um plug-in (por exemplo, um conftest
mó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.test
comando externo com segurança . Em vez disso, você deve agrupar a execução desse comando com um setuptools personalizadotest
comando que (em ordem):
- Patches de macaco da
_pytest
API privada .
- Chama a
pytest.main()
função pública para executar o py.test
comando.
Esta resposta corrige py.test -s
e --capture=no
opçõ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.test
quando 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 test
comando 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 test
també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.