如何使用unittest正确测试Python logger的配置及输出效果
问题原因
unittest.assertLogs会给目标logger临时插入一个独立的内存捕获handler,这个handler用的是默认格式化规则,输出格式固定为{日志级别}:{logger名称}:{日志内容},不会应用你自定义给StreamHandler的Formatter,所以你拿不到带时间戳的输出。- 你测试用例里写死了固定时间戳作为预期值,就算能拿到格式化后的输出,每次运行测试的时间都会变化,也不可能匹配。
推荐测试方案
方案1:测试核心配置逻辑(推荐)
不需要验证logging标准库的Formatter功能是否正常,只需要验证你的配置是否生效、日志是否按预期输出即可,这是工业界通用的测试逻辑:
import logging def test_setup_logger(self): # 每次测试前清空原有handler,避免历史测试带来的污染 LOGGER.handlers.clear() with self.assertLogs(LOGGER, level='DEBUG') as cm: setup_logger(level=logging.DEBUG) # 验证日志内容、级别正确 log_record = cm.records[0] self.assertEqual(log_record.levelno, logging.DEBUG) self.assertEqual(log_record.getMessage(), 'Logger is set up...') # 验证logger级别配置正确 self.assertEqual(LOGGER.level, logging.DEBUG) # 验证handler已正确添加 self.assertEqual(len(LOGGER.handlers), 1) added_handler = LOGGER.handlers[0] self.assertIsInstance(added_handler, logging.StreamHandler) self.assertEqual(added_handler.level, logging.DEBUG) # 验证formatter配置符合预期 formatter = added_handler.formatter self.assertEqual(formatter._fmt, '%(asctime)s %(levelname)s: %(message)s') self.assertEqual(formatter.datefmt, '%Y-%m-%d %H:%M:%S')
方案2:验证实际格式化输出
如果你确实需要验证最终控制台输出的格式是否符合要求,可以自行捕获标准输出,用正则匹配动态时间戳:
import logging import io import sys import re def test_setup_logger_formatted_output(self): LOGGER.handlers.clear() # 重定向标准输出到内存流 captured_stream = io.StringIO() original_stdout = sys.stdout sys.stdout = captured_stream try: setup_logger(level=logging.DEBUG) output = captured_stream.getvalue().strip() finally: # 恢复标准输出 sys.stdout = original_stdout # 正则匹配时间格式和固定内容,避开动态时间戳 expected_pattern = r'^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2} DEBUG: Logger is set up\.\.\.$' self.assertRegex(output, expected_pattern)
注意事项
每次调用setup_logger都会给logger新增一个handler,多次调用会导致同一条日志重复输出,生产环境使用时建议加重复handler判断,避免重复添加。
内容的提问来源于stack exchange,提问作者Boris Kalinin
相关产品推荐
相关产品推荐

