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的日志合并写入每个测试用例对应的单个日志文件。
问题原因
- 模块级logger初始化时机冲突:
test_file.py作为测试入口模块,在pytest启动阶段就会被导入,模块级的logger = logging.getLogger(__name__)会在pytest_runtest_setup钩子执行前完成初始化。此时logging-plugin尚未设置文件handler,这个logger绑定的是pytest初始的root logger handler,不会写入后续创建的测试日志文件。 - 业务模块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
相关产品推荐
相关产品推荐

