pytest合集(12)— 日志管理

一、logging 日志管理模块

logging日志模块此文不做详细说明,这里主要介绍几个重要概念。

1、日志级别

NOTSET<DEBUG < INFO < WARNING < ERROR < CRITICAL

2、format日志格式

  • %(levelno)s: 打印日志级别的数值
  • %(levelname)s: 打印日志级别名称
  • %(pathname)s: 打印当前执行程序的路径,其实就是sys.argv[0]
  • %(filename)s: 打印当前执行程序名
  • %(funcName)s: 打印日志的当前函数
  • %(module)s 调用日志输出函数的模块名
  • %(name)s : 所使用的日志名称,默认是'root',因为默认使用的是 rootLogger
  • %(msecs)d 日志事件发生事件的毫秒部分
  • %(lineno)d: 打印日志的当前行号
  • %(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
  • %(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
  • %(relativeCreated)d 日志事件发生的时间相对于logging模块加载时间的相对毫秒数(目前还不知道干嘛用的)
  • %(thread)d: 打印线程ID
  • %(threadName)s: 打印线程名称
  • %(process)d: 打印进程ID
  • %(message)s: 打印日志信息

二、Captured Log 捕获日志

默认情况,pytest会自动捕获WARNING级别或更高级别的日志消息(log)、标准输出(stdout)和标准错误输出(stderr),并将每个失败的测试或者发生异常的测试捕获到的内容逐个输出到控制台,成功的测试则不输出。

可以通过--show capture命令行选项配置此行为。

1、控制台输出捕获日志

  • Captured log call,捕获测试的日志消息,默认情况下,每个捕获的日志消息都会显示日志级别、模块、行号、消息。
  • Captured stdout call,捕获测试的标准输出,如print
  • Captured stderr call,捕获测试的标准错误输出

先来看个例子,新建test_log.py文件如下:

import logging
import sys


def test_func1():
    print("text going to stdout in test_func1")
    logging.info("info in test_func1")
    logging.warning("warnning in test_func1")
    logging.error("error in test_func1")
    print('text going to stderr in test_func1', file=sys.stderr)
    assert 1 == 2


def test_func2():
    print("text going to stdout in test_func2")
    logging.info("info in test_func2")
    logging.warning("warnning in test_func2")
    logging.error("error in test_func2")
    print('text going to stderr in test_func2', file=sys.stderr)
    assert 1 == 1

使用pytest运行这个文件结果如下:

Microsoft Windows [版本 10.0.19044.1889]
(c) Microsoft Corporation。保留所有权利。

(venv) C:\Users\057776\PycharmProjects\pytest-demo>pytest
================================== test session starts ==================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: C:\Users\057776\PycharmProjects\pytest-demo, configfile: pytest.ini, testpaths: testlog
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 2 items                                                                                                                                                   

testlog\test_log.py F.                                                                                                                               [100%]

===================================== FAILURES =====================================
_______________________________________ test_func1 _______________________________________

    def test_func1():
        print("text going to stdout in test_func1")
        logging.info("info in test_func1")
        logging.warning("warnning in test_func1")
        logging.error("error in test_func1")
        print('text going to stderr in test_func1', file=sys.stderr)
>       assert 1 == 2
E       assert 1 == 2

testlog\test_log.py:20: AssertionError
------------------------------------------------------------ Captured stdout call ------------------------------------------------------------
text going to stdout in test_func1
------------------------------------------------------------ Captured stderr call -------------------------------------------------------------
text going to stderr in test_func1
-------------------------------------------------------------- Captured log call --------------------------------------------------------------
WARNING  root:test_log.py:17 warnning in test_func1
ERROR    root:test_log.py:18 error in test_func1
================================= short test summary info =================================
FAILED testlog/test_log.py::test_func1 - assert 1 == 2
================================ 1 failed, 1 passed in 0.45s ================================

(venv) C:\Users\057776\PycharmProjects\pytest-demo>

分析运行结果:

test_func1测试失败,pytest将捕获消息内容输出到控制台,包含WARNING和ERROR级别的日志消息(Captured log call)、标准输出内容(Captured stdout call )、标准错误输出内容(Captured stderr call )。

pytest捕获的消息内容格式显示为:日志级别、模块、行号、消息。

2、--show-capture 控制捕获日志输出内容

--show-capture={no,stdout,stderr,log,all}
        Controls how captured stdout/stderr/log is shown on failed tests. Default is 'all'.

  • no:对于失败测试,不输出捕获内容(stdout、stderr 和日志)
  • stdout:对于失败测试,输出捕获的stdout内容
  • stderr:对于失败测试,输出捕获的stderr内容
  • log:对于失败测试,输出捕获的log内容
  • all:默认值,对于失败测试,输出捕获内容

还是test_log.py文件,使用pytest --show-capture=no来运行测试:

(venv) C:\Users\057776\PycharmProjects\pytest-demo>pytest --show-capture=no
================================= test session starts =================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: C:\Users\057776\PycharmProjects\pytest-demo, configfile: pytest.ini, testpaths: testlog
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 2 items                                                                                                                                                   

testlog\test_log.py F.                                                                                                                         [100%]

==================================== FAILURES ====================================
______________________________________ test_func1 ______________________________________

    def test_func1():
        print("text going to stdout in test_func1")
        logging.info("info in test_func1")
        logging.warning("warnning in test_func1")
        logging.error("error in test_func1")
        print('text going to stderr in test_func1', file=sys.stderr)
>       assert 1 == 2
E       assert 1 == 2

testlog\test_log.py:20: AssertionError
================================ short test summary info ================================
FAILED testlog/test_log.py::test_func1 - assert 1 == 2
=============================== 1 failed, 1 passed in 0.35s ===============================

(venv) C:\Users\057776\PycharmProjects\pytest-demo>

运行结果可知,test_func1测试失败,但是由于--show-capture=no,控制台没有输出捕获的日志内容。

3、--capture=method 设置捕获日志方式

--capture=method per-test capturing method: one of fd|sys|no|tee-sys.

  • --capture=fd :默认模式,在文件描述符级别捕获输出,这意味着写入文件的描述符 1(stdout)和 2(stderr)的所有输出都被捕获。
  • --capture=no :禁用对标准输出、标准错误以及日志消息捕获。-s :禁用所有捕获,等同于--capture=no
  • --capture=sys :仅对python的sys.stdout和sys.stderr进行捕获,而不是对文件描述符的写入进行捕获。可以用来解决问题,pytest-html输出的HTML测试报告中的"No log output captured"
  • --capture=tee-sys :对python的sys.stdout和sys.stderr进行捕获,并且会继续传递给系统,参考tee命令的作用。这样在捕获一份的同时,还能实时打印输出。

4、设置捕获日志级别和消息格式

默认情况下,pytest捕获的消息内容格式显示为:日志级别、模块、行号、消息。

在pytest.ini文件中设置日志捕获的格式如下:

log_level = INFO

log_format = %(asctime)s %(levelname)s %(message)s

log_date_format = %Y-%m-%d %H:%M:%S

说明:

  • log_level = INFO,设置捕获日志的日志级别。可以使用整数值或级别名称。
  • log_date_format = %Y-%m-%d %H:%M:%S,设置捕获日志的日期格式
  • log_format = %(asctime)s %(levelname)s %(message)s,设置捕获日志的消息格式。

配置好pytest.ini文件之后,再次运行test_log.py文件结果如下:

(venv) C:\Users\057776\PycharmProjects\pytest-demo>pytest
================================== test session starts ==================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1
rootdir: C:\Users\057776\PycharmProjects\pytest-demo, configfile: pytest.ini, testpaths: testlog
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 2 items                                                                                                                                                   

testlog\test_log.py F.                                                                                                                              [100%]

===================================== FAILURES =====================================
_______________________________________ test_func1 _______________________________________

    def test_func1():
        print("text going to stdout in test_func1")
        logging.info("info in test_func1")
        logging.warning("warnning in test_func1")
        logging.error("error in test_func1")
        print('text going to stderr in test_func1', file=sys.stderr)
>       assert 1 == 2
E       assert 1 == 2

testlog\test_log.py:20: AssertionError
----------------------------------------------------------- Captured stdout call -----------------------------------------------------------
text going to stdout in test_func1
----------------------------------------------------------- Captured stderr call -----------------------------------------------------------
text going to stderr in test_func1
------------------------------------------------------------- Captured log call -------------------------------------------------------------
2022-08-29 18:17:57 INFO info in test_func1
2022-08-29 18:17:57 WARNING warnning in test_func1
2022-08-29 18:17:57 ERROR error in test_func1
================================= short test summary info ================================
FAILED testlog/test_log.py::test_func1 - assert 1 == 2
=============================== 1 failed, 1 passed in 0.40s ================================

(venv) C:\Users\057776\PycharmProjects\pytest-demo>

运行结果可知, Captured log call -日志详细跟pytest.ini配置文件一致。

三、Live Log 实时日志

可以设置配置选项log_cli = True,在测试运行期间启用实时日志,并输出实时日志到控制台。

1、设置实时日志级别和消息格式

  • log_cli = True,在测试运行期间启用实时日志。默认值为False,不输出实时日志。设置为True,输出实时日志到控制台。
  • log_cli_level = INFO,设置实时日志的日志级别,可以使用整数值或级别名称。
  • log_cli_date_format = %Y-%m-%d %H:%M:%S,设置实时日志的日期格式
  • log_cli_format = %(asctime)s %(levelname)s %(message)s,设置实时日志的消息格式

pytest.ini文件如下:

log_cli = True log_cli_level = INFO

log_cli_date_format = %Y-%m-%d %H:%M:%S

log_cli_format = %(asctime)s %(levelname)s %(message)s

为了避免捕获日志输出到控制台的干扰使用命令行参数 :--show-capture=no 不显示Captured log日志。

运行test_log.py文件如下:

也可以直接使用命令参数不用pytest.ini配置文件:pytest -o log_cli=True

Microsoft Windows [版本 10.0.19044.1889]
(c) Microsoft Corporation。保留所有权利。

(venv) C:\Users\057776\PycharmProjects\pytest-demo>pytest -o log_cli=True
==================================== test session starts ====================================
platform win32 -- Python 3.8.8, pytest-6.2.3, py-1.10.0, pluggy-0.13.1 -- e:\programs\python\python38\python.exe
cachedir: .pytest_cache
metadata: {'Python': '3.8.8', 'Platform': 'Windows-10-10.0.19041-SP0', 'Packages': {'pytest': '6.2.3', 'py': '1.10.0', 'pluggy': '0.13.1'}, 'Plugins': {'html': '3.1.1', 'metadata': '1.11.0', 'rerunfailures': '9.1.1', 'assume': '2.2.0', 'requests-mock': '1.7.0'}, 'JAVA_HOME': 'C:\\Program Files\\Java\\jdk1.8.0_271', 'foo': 'bar'}

rootdir: C:\Users\057776\PycharmProjects\pytest-demo, configfile: pytest.ini, testpaths: testlog
plugins: html-3.1.1, metadata-1.11.0, rerunfailures-9.1.1, assume-2.2.0, requests-mock-1.7.0
collected 2 items                                                                                                                                                   

testlog/test_log.py::test_func1 text going to stdout in test_func1

-------------------------------------------------------------------- live log call --------------------------------------------------------------------
2022-08-29 18:38:35 INFO info in test_func1
2022-08-29 18:38:35 WARNING warnning in test_func1
2022-08-29 18:38:35 ERROR error in test_func1
text going to stderr in test_func1
FAILED
testlog/test_log.py::test_func2 text going to stdout in test_func2

-------------------------------------------------------------------- live log call --------------------------------------------------------------------
2022-08-29 18:38:35 INFO info in test_func2
2022-08-29 18:38:35 WARNING warnning in test_func2
2022-08-29 18:38:35 ERROR error in test_func2
text going to stderr in test_func2
PASSED

======================================= FAILURES =======================================
_________________________________________ test_func1 _________________________________________

    def test_func1():
        print("text going to stdout in test_func1")
        logging.info("info in test_func1")
        logging.warning("warnning in test_func1")
        logging.error("error in test_func1")
        print('text going to stderr in test_func1', file=sys.stderr)
>       assert 1 == 2
E       assert 1 == 2
E         +1
E         -2

testlog\test_log.py:20: AssertionError
================================== short test summary info ==================================
FAILED testlog/test_log.py::test_func1 - assert 1 == 2
================================= 1 failed, 1 passed in 0.40s =================================

(venv) C:\Users\057776\PycharmProjects\pytest-demo>

运行结果可知,无论测试成功与否, 所有测试都输出了实时日志内容(live log call)。

2、将实时日志写入日志文件中

(1)设置日志文件路径和格式

  • log_file = logs/pytest-logs.txt,将实时日志写入文件中
  • log_file_level = INFO,写入文件的日志级别
  • log_file_date_format = %Y-%m-%d %H:%M:%S,写入文件的日期格式
  • log_file_format = %(asctime)s %(levelname)s %(message)s,写入文件的日志消息格式

pytest.ini文件如下:

log_file = logs/pytest-logs.txt

log_file_level = INFO

log_file_date_format = %Y-%m-%d %H:%M:%S

log_file_format = %(asctime)s %(levelname)s %(message)s

运行运行test_log.py文件结果如下:

运行结果可知,pytest将实时日志写入到了日志文件中。

3、自定义日志颜色

如果启用了彩色终端输出,则日志级别是彩色的。支持从默认颜色更改或在自定义日志级别上添加颜色add_color_level()。

例子:

@pytest.hookimpl
def pytest_configure(config):
    logging_plugin = config.pluginmanager.get_plugin("logging-plugin")

    # Change color on existing log level
    logging_plugin.log_cli_handler.formatter.add_color_level(logging.INFO, "cyan")

    # Add color to a custom log level (a custom log level `SPAM` is already set up)
    logging_plugin.log_cli_handler.formatter.add_color_level(logging.SPAM, "blue")

注意:

此功能及其 API 被认为是实验性的,可能会在版本之间发生更改,而不会发出弃用通知。

四、caplog fixture 内置夹具

caplog是pytest内置的夹具,用来访问和控制日志捕获。

API Reference — pytest documentation

How to manage logging — pytest documentation


reference:

How to capture stdout/stderr output — pytest documentation

How to manage logging — pytest documentation

来玩魔王的咚

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 好的,下面是一个简单的 pytest 测试实战: 假设我们有一个函数,接收两个数字参数并返回它们的乘积: ```python def multiply(a, b): return a * b ``` 我们可以使用 pytest 来编写测试用例,确保函数的行为符合预期。首先,我们需要创建一个名为 `test_multiply.py` 的文件,在其中编写测试用例。 ```python # test_multiply.py from multiply import multiply def test_multiply_positive_numbers(): result = multiply(2, 3) assert result == 6 def test_multiply_negative_numbers(): result = multiply(-2, -3) assert result == 6 def test_multiply_zero(): result = multiply(0, 5) assert result == 0 result = multiply(5, 0) assert result == 0 ``` 在这个测试用例中,我们创建了三个测试函数,分别测试两个正数相乘、两个负数相乘以及其中一个数为零的情况。使用 `assert` 关键字来断言函数的返回值是否符合预期。 运行测试用例,可以使用以下命令: ``` pytest test_multiply.py ``` 如果所有测试用例都通过,pytest 将输出以下内容: ``` ============================= test session starts ============================= platform linux -- Python 3.8.5, pytest-6.2.1, py-1.10.0, pluggy-0.13.1 rootdir: /path/to/test_directory plugins: anyio-2.2.0 collected 3 items test_multiply.py ... [100%] ============================== 3 passed in 0.01s ============================== ``` 如果有任何测试用例失败,pytest 将输出详细的错误信息,帮助您快速定位问题。 这就是一个简单的 pytest 测试实战,它可以帮助您编写可靠的测试用例以确保代码的正确性。 ### 回答2: pytest是一种Python的测试框架,它提供了一系列的方法和工具来编写和执行测试用例。pytest测试实战是指在实际项目中使用pytest进行测试的过程。 首先,我们可以使用pytest编写测试脚本。测试脚本可以包含多个测试用例,每个测试用例是一个以test_开头的函数。我们可以使用assert语句来断言测试的结果是否符合预期。pytest提供了丰富的断言方法,可以方便地进行各种断言操作。 其次,我们可以使用pytest的fixture功能来创建和管理测试的前置条件。fixture可以用来模拟测试环境和数据,使测试用例的编写更加简洁和灵活。我们可以在测试用例中使用fixture来获取测试数据或者创建测试环境,从而减少重复的代码。 另外,pytest还提供了参数化测试的功能,可以通过参数化的方式运行同一个测试用例的多组测试数据。这样可以提高测试覆盖率,减少测试代码的编写量。 pytest还支持多线程和分布式测试,可以实现并发执行测试用例,提高测试效率。同时,pytest还提供了详细的测试报告和日志功能,方便我们查看和分析测试结果。 最后,使用pytest进行测试实战时,我们可以根据项目的需要进行自定义的插件开发。pytest提供了丰富的插件接口,可以轻松扩展pytest的功能和特性。 总而言之,pytest测试实战是指在实际项目中使用pytest进行测试的过程。通过使用pytest,我们可以简洁高效地编写和执行测试用例,提高测试效率,并且可以根据项目的需要进行自定义的插件开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值