在Python代码中运行pytest,如何将会话结果写入日志文件?
问题
通过Python脚本运行pytest时,尝试将pytest会话输出(测试摘要、用例收集信息、失败详情等)写入日志文件,但当前日志文件仅包含测试代码中logging模块输出的信息,和控制台输出不一致。
代码与运行情况
test_functions.py
import pytest import logging LOGGER = logging.getLogger(__name__) @pytest.fixture def input_value(): input = 39 return input def test_divisible_by_3(input_value): LOGGER.info('Running the test 1') assert input_value % 3 == 0 def test_divisible_by_6(input_value): LOGGER.info('Running the test 2') assert input_value % 6 == 0
script.py
import pytest import logging log = logging.getLogger(__name__) pytest.main(args= ["test_functions.py","--log-level=DEBUG","--log-file=py_test_report.log"])
执行命令
python script.py
问题现象
- 控制台输出包含完整的pytest会话信息(平台信息、用例收集结果、测试进度、失败堆栈、测试摘要等)
- 日志文件
py_test_report.log仅包含测试代码中LOGGER.info的输出,缺少会话相关核心内容
解决方案
核心原因:--log-file参数仅负责捕获pytest的logging模块日志,而pytest的核心会话输出属于系统标准输出(stdout)和标准错误(stderr),不会被该参数捕获。要让日志文件与控制台内容完全一致,需要同时捕获这两部分输出。
方法1:在脚本中重定向stdout/stderr
修改script.py,自定义输出流同时写入文件和控制台,确保所有内容同步记录:
import pytest import sys class DualOutput: def __init__(self, filename): self.console = sys.stdout self.file = open(filename, 'w', encoding='utf-8') def write(self, message): self.console.write(message) self.file.write(message) def flush(self): self.console.flush() self.file.flush() # 重定向标准输出和错误流 sys.stdout = DualOutput('py_test_report.log') sys.stderr = sys.stdout # 运行pytest,移除--log-file避免重复记录logging输出 pytest.main(args=["test_functions.py", "--log-level=INFO"])
方法2:命令行层面重定向输出
如果允许在命令行完成输出重定向,可直接运行脚本时将所有输出写入文件:
python script.py > py_test_report.log 2>&1
同时修改script.py去掉--log-file参数:
import pytest pytest.main(args=["test_functions.py", "--log-level=INFO"])
方法3:pytest钩子自定义输出(进阶)
通过pytest的钩子函数(如pytest_terminal_summary)在conftest.py中实现会话信息的自定义写入,适合需要定制输出格式的场景,示例如下:
# conftest.py import logging LOGGER = logging.getLogger("pytest_session") LOGGER.addHandler(logging.FileHandler("py_test_report.log", encoding='utf-8')) LOGGER.setLevel(logging.INFO) def pytest_terminal_summary(terminalreporter, exitstatus, config): # 收集并写入会话摘要 LOGGER.info("\n" + terminalreporter._get_terminal_summary()) # 写入失败详情 for failed in terminalreporter.stats.get('failed', []): LOGGER.info(f"\nFAILURE DETAILS:\n{failed.longrepr}")
内容的提问来源于stack exchange,提问作者Tilak Mallikarjun
相关产品推荐
相关产品推荐

