158

我想在测试函数中放置一些日志语句来检查一些状态变量。

我有以下代码片段:

import pytest,os
import logging

logging.basicConfig(level=logging.DEBUG)
mylogger = logging.getLogger()

#############################################################################

def setup_module(module):
    ''' Setup for the entire module '''
    mylogger.info('Inside Setup')
    # Do the actual setup stuff here
    pass

def setup_function(func):
    ''' Setup for test functions '''
    if func == test_one:
        mylogger.info(' Hurray !!')

def test_one():
    ''' Test One '''
    mylogger.info('Inside Test 1')
    #assert 0 == 1
    pass

def test_two():
    ''' Test Two '''
    mylogger.info('Inside Test 2')
    pass

if __name__ == '__main__':
    mylogger.info(' About to start the tests ')
    pytest.main(args=[os.path.abspath(__file__)])
    mylogger.info(' Done executing the tests ')

我得到以下输出:

[bmaryada-mbp:/Users/bmaryada/dev/platform/main/proto/tests/tpch $]python minitest.py
INFO:root: About to start the tests 
======================================================== test session starts =========================================================
platform darwin -- Python 2.6.2 -- pytest-2.0.0
collected 2 items 

minitest.py ..

====================================================== 2 passed in 0.01 seconds ======================================================
INFO:root: Done executing the tests 

请注意,只有来自该'__name__ == __main__'块的日志消息才会传输到控制台。

有没有办法强制pytest从测试方法向控制台发出日志记录?

4

7 回答 7

229

从 3.3 版本开始,pytest支持实时日志记录,这意味着测试中发出的所有日志记录都将立即打印到终端。该功能记录在实时日志部分。默认情况下禁用实时日志记录;要启用它,log_cli = 1请在pyproject.toml1pytest.ini2配置中设置。实时日志支持发送到终端和文件;相关选项允许自定义记录:

终端:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

文件:

  • log_file
  • log_file_level
  • log_file_format
  • log_file_date_format

注意log_cli标志不能从命令行传递,必须pytest.ini. 所有其他选项都可以从命令行传递或在配置文件中设置。正如Kévin Barré此评论中指出的那样,可以通过该选项从命令行覆盖 ini-o/--override选项。因此,您可以简单地调用,而不是声明log_cliin pytest.ini

$ pytest -o log_cli=true ...

例子

用于演示的简单测试文件:

# test_spam.py

import logging

LOGGER = logging.getLogger(__name__)


def test_eggs():
    LOGGER.info('eggs info')
    LOGGER.warning('eggs warning')
    LOGGER.error('eggs error')
    LOGGER.critical('eggs critical')
    assert True

如您所见,不需要额外的配置;将根据在命令行中指定或从命令行传递的pytest选项自动设置记录器。pytest.ini

实时记录到终端、INFO级别、精美的输出

中的配置pyproject.toml

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "INFO"
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"

legacy 中的相同配置pytest.ini

[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S

运行测试:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
2018-08-01 14:33:20 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:33:20 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:33:20 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:33:20 [CRITICAL] eggs critical (test_spam.py:10)
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

实时记录到终端和文件,终端中只有消息和级别,文件CRITICAL中的精美输出pytest.log

中的配置pyproject.toml

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "CRITICAL"
log_cli_format = "%(message)s"

log_file = "pytest.log"
log_file_level = "DEBUG"
log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_file_date_format = "%Y-%m-%d %H:%M:%S"

legacy 中的相同配置pytest.ini

[pytest]
log_cli = 1
log_cli_level = CRITICAL
log_cli_format = %(message)s

log_file = pytest.log
log_file_level = DEBUG
log_file_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_file_date_format=%Y-%m-%d %H:%M:%S

测试运行:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
eggs critical
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

$ cat pytest.log
2018-08-01 14:38:09 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:38:09 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:38:09 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:38:09 [CRITICAL] eggs critical (test_spam.py:10)

1 pyproject.toml自 6.0 版起支持,是 IMO 的最佳选择。有关规格,请参阅PEP 518

2虽然您也可以pytestsetup.cfg[tool:pytest]部分下进行配置,但当您想提供自定义实时日志记录格式时,不要试图这样做。其他阅读工具setup.cfg可能会将诸如字符串插值之类的东西%(message)s视为失败。最好的选择是pyproject.toml无论如何都要使用,但如果你被迫使用传统的 ini 样式格式,请坚持pytest.ini以避免错误。

于 2018-08-01T12:43:29.227 回答
40

对我有用,这是我得到的输出:[snip -> 示例不正确]

编辑:您似乎必须将-s选项传递给 py.test,这样它就不会捕获标准输出。在这里(py.test 未安装),使用 python pytest.py -s pyt.py.

-s对于您的代码,您args只需要传入main

 pytest.main(args=['-s', os.path.abspath(__file__)])

请参阅有关捕获输出的 py.test 文档。

于 2011-01-12T20:14:04.580 回答
19

使用pytest --log-cli-level=DEBUGpytest-6.2.2 效果很好

于 2021-02-01T15:15:25.250 回答
7

要打开记录器输出,请使用--capture=no命令行中的发送标志。 --capture=no将显示记录器和打印语句的所有输出。如果您想从记录器捕获输出而不是打印语句,请使用--capture=sys

pytest --capture=no tests/system/test_backoffice.py

是有关“捕获 stdout/stderr 输出”的更多信息

默认情况下,记录器输出级别是“警告”来更改日志输出级别使用--log-cli-level标志。

pytest --capture=no --log-cli-level=DEBUG tests/system/test_backoffice.py
于 2021-02-03T16:30:36.403 回答
3

如果你想用命令行过滤日志,你可以通过--log-cli-level (pytest --log-cli-level) 并且日志将从你指定的级别及以上显示

(例如pytest --log-cli-level=INFO将显示 INFO 及以上日志(警告、错误、严重))

请注意:默认 --log-cli-level 是一个警告,如果你不指定它(https://docs.pytest.org/en/6.2.x/logging.html

但是如果您不想每次使用 pytest 时都使用--log-cli-level ,您可以 在 pytest 配置文件 (pytest.ini/tox.ini/setup.cfg)中设置日志级别

例如

log-level=INFO放入 pytest.ini (或我提到的其他配置文件)

当您运行pytest时,您只会看到 INFO 及以上的日志

于 2021-08-14T10:30:55.453 回答
1

如果您使用vscode,请使用以下配置,假设您已经为您的 Python 项目安装了 Python 官方插件( ms-python.python)。

./.vscode/setting.json在你的项目下

{
  ....
  "python.testing.pytestArgs": ["-s", "src"], //here before discover-path src
  "python.testing.unittestEnabled": false,
  "python.testing.nosetestsEnabled": false,
  "python.testing.pytestEnabled": true,
  ...
}

PS 一些插件可以使用它,包括但不限于

  • Visual Studio Code 的 Python 测试资源管理器( littlefoxteam.vscode-python-test-adapter)
  • Visual Studio Code 的测试资源管理器( hbenl.vscode-test-explorer)
于 2021-07-10T10:34:30.270 回答
0

您可以阅读: 用于登录 pytest 的文档
这是一个简单的示例,您可以运行并从 foo 函数获取日志。

#./test_main.py
from main import foo
import logging

def test_foo(caplog):
    caplog.set_level(logging.INFO)

    logging.getLogger().info('Log inside a test function!')

    assert foo(1, 2) == 5
    /* your test here*/
# ./main.py
import logging

def foo(a, b):
    logging.getLogger().info('a: ' + str(a))
    logging.getLogger().info('b: ' + str(b))
    return a + b

现在您可以运行 pytest 并从您需要的函数中获取日志信息。
如果您没有任何错误,则将省略日志。

于 2021-07-30T02:23:48.433 回答