是的,caplog 是 pytest 内置 fixture,无需安装或导入,但默认仅捕获 WARNING 及以上级别日志;INFO/DEBUG 需显式调用 caplog.set_level("INFO") 或配置 log_cli_level = INFO 才能被捕获和断言。

caplog fixture 在 pytest 中默认可用吗
是的,caplog 是 pytest 内置 fixture,无需额外安装或导入,只要用的是 pytest ≥ 3.7 就能直接在测试函数参数里写 caplog。但要注意:它默认只捕获 WARNING 及以上级别日志,INFO 和 DEBUG 不会出现在 caplog.records 或 caplog.text 里。
常见错误现象:caplog.text 为空,或 caplog.records 长度为 0,即使代码里明明调用了 logger.info("hello")。
- 必须显式设置日志级别,比如在测试函数开头加
caplog.set_level("INFO") - 也可以在
pytest.ini或pyproject.toml中全局配置:log_level = INFO - 如果测试中用的是模块级 logger(如
logging.getLogger(__name__)),确保没被其他 handler 干扰(比如 root logger 被重置过)
如何断言某条日志是否被输出
最直接的方式是检查 caplog.records 列表,它包含 LogRecord 实例,每个都有 .levelname、.message、.funcName 等属性。
示例:
立即学习“Python免费学习笔记(深入)”;
def test_user_login(caplog):
caplog.set_level("INFO")
login("alice")
assert len(caplog.records) == 1
assert caplog.records[0].levelname == "INFO"
assert "alice logged in" in caplog.records[0].message
注意点:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 不要用
caplog.text做精确匹配——它带换行和格式前缀(如INFO root:test_auth.py:24: alice logged in),容易因空格/路径变动而失败 - 避免直接用
assert "alice logged in" in caplog.text,可读性差且脆弱 - 如果要检查多条日志,建议用列表推导或
any(),比如:assert any("failed" in r.message for r in caplog.records)
caplog 为什么有时捕获不到第三方库的日志
因为 caplog 默认只作用于当前测试作用域的 logger 层级,而很多第三方库(如 requests、urllib3)使用独立的 logger 名称(如 "urllib3.connectionpool"),它们的 level 可能仍是 WARNING,或者根本没被 caplog 的 handler 绑定到。
解决办法:
- 显式指定 logger 名称:
caplog.set_level("DEBUG", logger="urllib3") - 或者用更宽泛的名称:
caplog.set_level("DEBUG", logger="requests") - 极端情况可临时启用 root logger:
caplog.set_level("DEBUG", logger=None)(不推荐长期用,太宽泛)
验证是否生效:在测试里加一句 print([r.name for r in caplog.records]),看记录的 name 是否符合预期。
caplog 和 logging.basicConfig() 冲突怎么办
如果项目启动时调用了 logging.basicConfig()(比如在 conftest.py 或主模块里),它会自动给 root logger 加一个 StreamHandler,导致日志被重复输出,甚至干扰 caplog 捕获——因为 caplog 是通过临时添加一个 Handler 实现的,多个 handler 共存时行为不可控。
实操建议:
- 在
conftest.py的pytest_configurehook 中禁用默认 handler:logging.getLogger().handlers.clear() - 或者改用
dictConfig精确控制测试环境日志配置,避免调用basicConfig - 测试函数内部不要调用
basicConfig;如果必须初始化,加force=True参数,并确保只执行一次
真正麻烦的不是 caplog 本身,而是日志系统状态在测试间残留——比如某个测试改了 root logger level,下一个测试就继承了这个状态。最好在每个测试开始前用 caplog.set_level(...) 显式重置,而不是依赖全局配置。

















