如何使用Pytest禁止日志写入文件并捕获日志做断言
问题解决方案
核心原因
你遇到的两个问题来自两处配置错误:
- 库的
__init__.py在导入阶段直接执行了日志配置,pytest运行测试导入库时就已经挂载了FileHandler,所以所有测试生成的日志都会写入文件 - 你的logging配置中将
library.modulelogger的propagate属性设为了no,Pytest的caplogfixture默认通过挂载在根logger的临时handler捕获日志,日志不向上传播自然无法被caplog捕获,导致caplog.text为空
解决方案
方案一:不修改原有业务代码,仅通过Pytest配置修复
在tests目录下新建conftest.py,添加以下自动生效的全局fixture,在测试启动阶段覆盖原有日志配置:
import logging import pytest from unittest.mock import patch @pytest.fixture(autouse=True, scope="session") def fix_logging_config_for_test(): # mock日志配置方法,阻止导入库时加载文件handler with patch("logging.config.dictConfig"): # 提前导入库,避免后续测试导入时触发原配置 import library.module # 修改目标logger配置 test_logger = logging.getLogger("library.module") # 打开日志传播,允许caplog捕获内容 test_logger.propagate = True # 移除所有已挂载的handler,禁止日志写入文件 for handler in test_logger.handlers[:]: test_logger.removeHandler(handler) # 保持日志级别与原配置一致 test_logger.setLevel(logging.DEBUG)
修改你的测试用例,指定caplog捕获的日志级别即可正常断言:
import library.module class TestFunction: def test_something_else(self): library.module.function() assert True def test_logs(self, caplog): # 指定捕获library.module logger的INFO及以上级别日志 caplog.set_level(logging.INFO, logger="library.module") library.module.function() assert "desired" in caplog.text
方案二:优化库的日志初始化逻辑(推荐)
库不应该在导入阶段替用户配置日志,这会和使用方的日志配置产生冲突,属于不良实践。修改library/__init__.py将日志配置改为主动触发的方法:
import logging.config import yaml import os def init_logging(config_path: str = "logging.yaml"): if os.path.exists(config_path): with open(config_path) as f: conf_dict = yaml.safe_load(f) logging.config.dictConfig(conf_dict) # 仅在直接运行模块时自动初始化日志 if __name__ == "__main__": init_logging()
业务代码使用库时主动调用library.init_logging()初始化日志即可,测试阶段导入库不会自动加载文件handler,直接使用caplog即可正常捕获日志。
内容的提问来源于stack exchange,提问作者Alvaro Aguilar
相关产品推荐
相关产品推荐

