Django 跑单元测试时如何禁用日志输出?
Django 测试时静音日志的三种方式:logging.disable(logging.CRITICAL) 全局开关、在 settings.py 中判断 test 命令自动禁用、用 logging filter 精细控制。
最快的方式是在 settings.py 里判断是否在跑测试:如果是 manage.py test 启动,就执行 logging.disable(logging.CRITICAL),抑制 CRITICAL 及以下标准日志级别(自定义更高等级除外);之后 Django 测试运行器输出的错误信息不受影响。
方法一:settings.py 自动判断(推荐)
import sys
import logging
if len(sys.argv) > 1 and sys.argv[1] == 'test':
logging.disable(logging.CRITICAL)
此判断仅识别参数位置符合示例的 manage.py test,不识别 pytest 或任意自定义 runner;更稳定的项目可用独立测试 settings。这样平时开发日志照常,跑测试时自动安静,无需手动切换。
方法二:测试代码里手动禁用
在测试基类或 setUp 中:
import logging
previous = logging.root.manager.disable
logging.disable(logging.CRITICAL)
try:
... # 测试操作
finally:
logging.disable(previous) # 恢复原阈值,而非假设 NOTSET
方法三:logging filter 精细控制
在 settings.py 的 LOGGING 配置中自定义 filter,只过滤特定 logger 或特定消息,而不是抑制 CRITICAL 及以下标准日志级别(自定义更高等级除外):
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'filters': {
'no_sql': {
'()': 'django.utils.log.CallbackFilter',
'callback': lambda r: not (r.name == 'django.db.backends' or r.name.startswith('django.db.backends.')),
},
},
'handlers': {
'console': {
'class': 'logging.StreamHandler',
'filters': ['no_sql'],
},
},
'root': {'handlers': ['console'], 'level': 'INFO'},
}
还需将 console handler 绑定到实际生效的 logger/root;若已有其他 handler,需分别检查过滤规则。适合只想屏蔽 SQL 日志等特定噪音的场景。
常见问题(FAQ)
Q:禁用日志后测试失败时还看得到报错吗?
A:看得到。测试框架自身的断言输出不走 logging 模块,logging.disable 只影响 logging 产生的消息。
Q:Django 测试默认会怎么处理 logging?
A:Django 启动时按 LOGGING_CONFIG 指定的配置函数应用 LOGGING,测试并不自动静音全部日志;测试通常使用 DEBUG=False,SQL 日志还受 force_debug_cursor 等设置影响。
Q:想断言"某处确实打了日志"怎么办?
A:用 self.assertLogs('logger名', level='INFO') 上下文管理器,这是 Django/Python 测试断言日志的标准方式,全局 disable 会阻止它捕获被禁用的记录;进入 assertLogs 前应临时 logging.disable(logging.NOTSET),结束后用 finally/测试 cleanup 恢复原阈值。
[1]: 观测云文档《日志查看器》https://docs.guance.com/logs/explorer/