Python 如何保存pytest';将结果/日志保存到文件中?

Python 如何保存pytest';将结果/日志保存到文件中?,python,logging,pytest,Python,Logging,Pytest,我在试图将pytest显示的所有结果保存到一个文件(txt、log,无所谓)时遇到了问题。在下面的测试示例中,我想将console中显示的内容捕获到某种文本/日志文件中: import pytest import os def test_func1(): assert True def test_func2(): assert 0 == 1 if __name__ == '__main__': pytest.main(args=['-sv', os.path.a

我在试图将pytest显示的所有结果保存到一个文件(txt、log,无所谓)时遇到了问题。在下面的测试示例中,我想将console中显示的内容捕获到某种文本/日志文件中:

import pytest
import os

def test_func1():
    assert True


def test_func2():
    assert 0 == 1

if __name__ == '__main__':

    pytest.main(args=['-sv', os.path.abspath(__file__)])
要保存到文本文件的控制台输出:

test-mbp:hi_world ua$ python test_out.py
================================================= test session starts =================================================
platform darwin -- Python 2.7.6 -- py-1.4.28 -- pytest-2.7.1 -- /usr/bin/python
rootdir: /Users/tester/PycharmProjects/hi_world, inifile: 
plugins: capturelog
collected 2 items 

test_out.py::test_func1 PASSED
test_out.py::test_func2 FAILED

====================================================== FAILURES =======================================================
_____________________________________________________ test_func2 ______________________________________________________

    def test_func2():
>       assert 0 == 1
E       assert 0 == 1

test_out.py:9: AssertionError
========================================= 1 failed, 1 passed in 0.01 seconds ==========================================
test-mbp:hi_world ua$ 

看起来您的所有测试输出都是标准输出,所以您只需要在那里“重定向”python调用的输出:

python test_out.py >myoutput.log
您还可以将输出“T”到多个位置。例如,您可能希望登录到该文件,但也可以在控制台上看到输出。然后,上述示例变为:

python test_out.py | tee myoutput.log
内部插件正是这样做的,但将输出直接发送到bpaste.net。您可以查看插件实现,了解如何根据您的需要重用它。

我根据Bruno Oliveira的建议得出这一结论:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
Pytest Plugin that save failure or test session information to a file pass as a command line argument to pytest.

It put in a file exactly what pytest return to the stdout.

To use it :
Put this file in the root of tests/ edit your conftest and insert in the top of the file :

    pytest_plugins = 'pytest_session_to_file'

Then you can launch your test with the new option --session_to_file= like this :

    py.test --session_to_file=FILENAME
Or :
    py.test -p pytest_session_to_file --session_to_file=FILENAME


Inspire by _pytest.pastebin
Ref: https://github.com/pytest-dev/pytest/blob/master/_pytest/pastebin.py

Version : 0.1
Date : 30 sept. 2015 11:25
Copyright (C) 2015 Richard Vézina <ml.richard.vezinar @ gmail.com>
Licence : Public Domain
"""

import pytest
import sys
import tempfile


def pytest_addoption(parser):
    group = parser.getgroup("terminal reporting")
    group._addoption('--session_to_file', action='store', metavar='path', default='pytest_session.txt',
                     help="Save to file the pytest session information")


@pytest.hookimpl(trylast=True)
def pytest_configure(config):
    tr = config.pluginmanager.getplugin('terminalreporter')
    # if no terminal reporter plugin is present, nothing we can do here;
    # this can happen when this function executes in a slave node
    # when using pytest-xdist, for example
    if tr is not None:
        config._pytestsessionfile = tempfile.TemporaryFile('w+')
        oldwrite = tr._tw.write

        def tee_write(s, **kwargs):
            oldwrite(s, **kwargs)
            config._pytestsessionfile.write(str(s))
        tr._tw.write = tee_write


def pytest_unconfigure(config):
    if hasattr(config, '_pytestsessionfile'):
        # get terminal contents and delete file
        config._pytestsessionfile.seek(0)
        sessionlog = config._pytestsessionfile.read()
        config._pytestsessionfile.close()
        del config._pytestsessionfile
        # undo our patching in the terminal reporter
        tr = config.pluginmanager.getplugin('terminalreporter')
        del tr._tw.__dict__['write']
        # write summary  
        create_new_file(config=config, contents=sessionlog)


def create_new_file(config, contents):
    """
    Creates a new file with pytest session contents.
    :contents: paste contents
    :returns: url to the pasted contents
    """
    # import _pytest.config
    # path = _pytest.config.option.session_to_file
    # path = 'pytest_session.txt'
    path = config.option.session_to_file
    with open(path, 'w') as f:
        f.writelines(contents)


def pytest_terminal_summary(terminalreporter):
    import _pytest.config
    tr = terminalreporter
    if 'failed' in tr.stats:
        for rep in terminalreporter.stats.get('failed'):
            try:
                msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc
            except AttributeError:
                msg = tr._getfailureheadline(rep)
            tw = _pytest.config.create_terminal_writer(terminalreporter.config, stringio=True)
            rep.toterminal(tw)
            s = tw.stringio.getvalue()
            assert len(s)
            create_new_file(config=_pytest.config, contents=s)
#/usr/bin/env python
#-*-编码:utf-8-*-
"""
Pytest插件,将失败或测试会话信息保存到文件中,作为Pytest的命令行参数传递。
它将pytest返回给stdout的内容放入一个文件中。
要使用它:
将此文件放在测试的根目录中/编辑conftest并插入文件的顶部:
pytest_插件='pytest_会话_到_文件'
然后,您可以使用新选项--session_to_file=启动测试,如下所示:
py.test——会话到文件=文件名
或:
py.test-p pytest_session_to_file——session_to_file=FILENAME
受_pytest.pastebin启发
裁判:https://github.com/pytest-dev/pytest/blob/master/_pytest/pastebin.py
版本:0.1
日期:2015年9月30日11:25
版权所有(C)2015 Richard Vézina
许可证:公共领域
"""
导入pytest
导入系统
导入临时文件
def pytest_addoption(解析器):
group=parser.getgroup(“终端报告”)
组。\添加选项('--session\u to_file',action='store',metavar='path',default='pytest\u session.txt',
help=“保存以归档pytest会话信息”)
@pytest.hookimpl(trylast=True)
def pytest_配置(配置):
tr=config.pluginmanager.getplugin('terminalreporter')
#如果没有终端报告器插件,我们在这里就无能为力;
#当此函数在从属节点中执行时,可能会发生这种情况
#例如,当使用pytest xdist时
如果tr不是无:
config._pytestsessionfile=tempfile.TemporaryFile('w+'))
oldswrite=tr.\u tw.write
def tee_书写,**kwargs:
oldwrite(s,**kwargs)
config._pytestsessionfile.write(str)
tr._tw.write=tee_write
def pytest_未配置(配置):
如果hasattr(配置,“\u pytestsessionfile”):
#获取终端内容并删除文件
config._pytestsessionfile.seek(0)
sessionlog=config.\u pytestsessionfile.read()
config._pytestsessionfile.close()
del config.\u pytestsessionfile
#撤消终端报告器中的修补程序
tr=config.pluginmanager.getplugin('terminalreporter')
del tr.u tw.uuu dict_uuuuuuu['write']
#写总结
创建新文件(config=config,contents=sessionlog)
def创建新文件(配置,内容):
"""
创建包含pytest会话内容的新文件。
:内容:粘贴内容
:返回粘贴内容的:url
"""
#导入_pytest.config
#path=\u pytest.config.option.session\u到\u文件
#路径='pytest_session.txt'
path=config.option.session\u到\u文件
打开(路径“w”)作为f:
f、 书写线(目录)
def pytest_terminal_摘要(terminalreporter):
导入_pytest.config
tr=终端报告器
如果tr.stats中的“失败”:
对于terminalreporter.stats.get('failed')中的rep:
尝试:
msg=rep.longrepr.reprtraceback.reprentries[-1].reprfileloc
除属性错误外:
msg=tr.\u getfailureheadline(代表)
tw=\u pytest.config.create\u terminal\u writer(terminalreporter.config,stringio=True)
代表终端(tw)
s=tw.stringio.getvalue()
(s)
创建新文件(config=\u pytest.config,contents=s)

这里有一个fixture为了让您能够做到这一点,我使用了pytest缓存功能,以便利用一个fixture,它可以传递给多个测试文件,包括分布式测试(xdist),以便能够收集和打印测试结果

conftest.py:

from _pytest.cacheprovider import Cache
from collections import defaultdict

import _pytest.cacheprovider
import pytest

@pytest.hookimpl(tryfirst=True)
def pytest_configure(config):
    config.cache = Cache(config)
    config.cache.set('record_s', defaultdict(list))

@pytest.fixture(autouse=True)
def record(request):
    cache = request.config.cache
    record_s = cache.get('record_s', {})
    testname = request.node.name
    # Tried to avoid the initialization, but it throws errors.
    record_s[testname] = []
    yield record_s[testname]
    cache.set('record_s', record_s)

@pytest.hookimpl(trylast=True)
def pytest_unconfigure(config):
    print("====================================================================\n")
    print("\t\tTerminal Test Report Summary: \n")
    print("====================================================================\n")
    r_cache = config.cache.get('record_s',{})
    print str(r_cache)
使用:

输出:

====================================================================

        Terminal Test Report Summary:

====================================================================

{u'test_foo': [[u'PASS',u'reason', { u'some': u'other_stuff' } ]]}

实际上,我正在打包这个pytest插件,最后找到了第三方插件列表(),我不确定我所做的与pytest capturelog或pytest catchlog不一样,插件的输出肯定不一样,尽管它可能提供相同的信息。如果知道这些插件的人可以确认。。。如果是这样,我最好添加从这些插件获得相同输出的功能,然后再添加上面的功能…这里是pypi包:最后是一个工作的pypi包这里是:如果调用pytest.main(),这也可以工作吗?我正试图保存pytest测试的输出,令人惊讶的是,这里几乎所有的答案都没有提到
pytest.main()
表单。谢谢我不明白为什么不。。。但是我没有尝试,因为我测试的东西没有成功地使用pytest.main()。。。所以我创建了自己的测试午餐脚本来减少锅炉板。。。注意,我从来没有时间更新pypi包,但是github repo中有Python3的修复程序……到目前为止,没有确切的答案似乎Windows 10中包含了
tee
====================================================================

        Terminal Test Report Summary:

====================================================================

{u'test_foo': [[u'PASS',u'reason', { u'some': u'other_stuff' } ]]}