You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pytest多模块日志问题:测试文件定义logger后日志文件为空

pytest日志文件为空及多模块日志合并写入解决方案

问题场景

项目结构

/dir
  py_pack_a
    __init__.py
    file_a.py

  py_pack_b
    __init__.py
    file_b.py

conftest.py
pytest.ini
test_file.py

当前配置代码

conftest.py(测试前设置日志文件)

@pytest.hookimpl
def pytest_runtest_setup(item):
    logging_plugin = item.config.pluginmanager.get_plugin("logging-plugin")
    timestamp = datetime.strftime(datetime.now(), '%Y-%m-%d_%H-%M-%S')
    logging_plugin.set_log_path(os.path.join('logs', f'{item.name}_{timestamp}.log'))

pytest.ini配置

[pytest]
addopts = -rA
log_cli = true

异常现象

仅在py_pack_a/file_a.py中用logger = logging.getLogger(__name__)定义logger时,日志能正常写入文件;但在test_file.py中用同样方式定义模块级logger后,生成的日志文件为空。

需求

实现file_a.py、file_b.py和test_file.py的日志合并写入每个测试用例对应的单个日志文件。


问题原因

  1. 模块级logger初始化时机冲突:test_file.py作为测试入口模块,在pytest启动阶段就会被导入,模块级的logger = logging.getLogger(__name__)会在pytest_runtest_setup钩子执行前完成初始化。此时logging-plugin尚未设置文件handler,这个logger绑定的是pytest初始的root logger handler,不会写入后续创建的测试日志文件。
  2. 业务模块logger时机适配:file_a.py的logger是在测试用例执行过程中(调用其函数时)才被实际使用/初始化,此时pytest_runtest_setup已经完成日志文件路径的设置,logging-plugin的文件handler已生效,所以日志能正常写入。

实现方法

方法一:延迟测试模块的logger初始化

不在test_file.py的模块级别定义logger,而是在测试函数内部或子函数中初始化,确保logger在pytest_runtest_setup执行后才创建:

# test_file.py
import logging
import py_pack_a.file_a
import py_pack_b.file_b

def test_demo():
    # 在测试函数内部初始化logger
    logger = logging.getLogger(__name__)
    logger.info("测试用例启动")
    
    # 调用业务模块函数,触发其日志输出
    py_pack_a.file_a.do_something()
    py_pack_b.file_b.do_something()
    
    logger.info("测试用例结束")

方法二:全局重配logger handler(推荐)

修改conftest.py,在设置日志路径后,重新配置root logger的handler,让所有已初始化的模块logger都继承新的文件handler,确保日志统一写入目标文件:

# conftest.py
import os
import datetime
import logging
import pytest

@pytest.hookimpl
def pytest_runtest_setup(item):
    # 初始化日志目录
    os.makedirs('logs', exist_ok=True)
    
    # 生成测试专属日志路径
    timestamp = datetime.datetime.strftime(datetime.datetime.now(), '%Y-%m-%d_%H-%M-%S')
    log_path = os.path.join('logs', f'{item.name}_{timestamp}.log')
    
    # 更新logging插件配置
    logging_plugin = item.config.pluginmanager.get_plugin("logging-plugin")
    logging_plugin.set_log_path(log_path)
    
    # 重置root logger的handler,避免重复输出
    root_logger = logging.getLogger()
    for handler in list(root_logger.handlers):
        root_logger.removeHandler(handler)
    
    # 添加文件handler,统一写入测试专属日志文件
    file_handler = logging.FileHandler(log_path, encoding='utf-8')
    log_formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    file_handler.setFormatter(log_formatter)
    root_logger.addHandler(file_handler)
    
    # 保留控制台输出(对应pytest.ini的log_cli=true)
    console_handler = logging.StreamHandler()
    console_handler.setFormatter(log_formatter)
    root_logger.addHandler(console_handler)
    
    # 设置全局日志级别(可根据需求调整为DEBUG/INFO等)
    root_logger.setLevel(logging.INFO)

验证方式

执行测试命令:

pytest test_file.py

每个测试用例都会在logs目录下生成对应名称的日志文件,其中包含test_file.py、file_a.py、file_b.py的所有日志内容。


内容的提问来源于stack exchange,提问作者user1911091

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.01 21:30:54