unittest与logging:捕获StreamHandler(sys.stdout)日志时captured.records为空的问题问询
问题1:为什么captured返回空值?
核心原因是你的日志输出发生在assertLogs上下文之外。当你在测试代码里导入MyCode模块时,模块顶层的logger.error('Started')代码就已经执行了——这时候你的测试函数test_logging里的assertLogs上下文还没启动呢!assertLogs只能捕获在它的with代码块内部产生的日志,所以之前输出的日志自然不会被记录到captured中,导致captured.records是空列表。
问题2:如何捕获发送到StreamHandler(sys.stdout)的日志?
要解决这个问题,你需要调整代码结构,让日志的产生落在assertLogs的上下文范围内,同时确保日志配置和测试逻辑兼容。下面是具体的修改方案:
步骤1:重构MyCode.py,将日志逻辑封装为函数
把模块顶层的日志触发代码放到函数里,这样可以在测试时手动控制它的执行时机:
import logging import sys def setup_logger(): """初始化日志配置""" logger = logging.getLogger() # 先清空已有handler,避免重复输出(可选但推荐) if logger.handlers: logger.handlers.clear() streamHandler = logging.StreamHandler(sys.stdout) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') streamHandler.setFormatter(formatter) logger.addHandler(streamHandler) # 设置日志级别,确保ERROR级别的日志能被捕获 logger.setLevel(logging.ERROR) return logger def log_started(): """触发需要测试的日志""" logger = logging.getLogger() logger.error('Started')
步骤2:修改测试代码,在assertLogs上下文内触发日志
调整测试逻辑,确保日志是在assertLogs的with块里产生的:
import unittest from unittest import TestCase import logging import MyCode class TestExample(TestCase): def setUp(self): # 测试前重置root日志器,避免其他测试或模块的配置干扰 self.root_logger = logging.getLogger() self.original_handlers = self.root_logger.handlers.copy() self.original_level = self.root_logger.level def tearDown(self): # 测试后恢复日志器的原始配置 self.root_logger.handlers = self.original_handlers self.root_logger.setLevel(self.original_level) def test_logging(self): # 初始化日志器 MyCode.setup_logger() # 使用assertLogs指定捕获ERROR级别及以上的日志 with self.assertLogs(level='ERROR') as captured: # 在上下文内触发日志 MyCode.log_started() # 断言日志记录数量 self.assertEqual(len(captured.records), 1) # 断言日志内容 self.assertTrue("Started" in captured.records[0].getMessage()) if __name__ == '__main__': unittest.main()
额外说明
assertLogs默认捕获WARNING及以上级别的日志,这里显式指定level='ERROR'是为了更清晰,也可以根据需要调整。- 在
setUp和tearDown中重置日志器配置,是为了避免不同测试用例之间的日志配置互相干扰,保证测试的独立性。 - 如果你的日志逻辑是业务代码的一部分,只需要确保在测试时,触发日志的代码执行在
assertLogs的上下文内即可,不用完全照搬上面的结构。
内容的提问来源于stack exchange,提问作者StressedBoi69420
相关产品推荐
相关产品推荐

