繁体   English   中英

用于 Python 记录器功能的单元测试

[英]Unittest for Python logger function

我正在尝试为类似这样的 create_logger(用户定义函数)编写单元测试。

create_logger(path,file_name):
            logger = logging.getLogger()
            logger.setLevel(logging.INFO)
            formatter = logging.Formatter(
                fmt="%(asctime)s %(levelname)s %(message)s",
                datefmt="%Y-%m-%d %H:%M:%S",
            )

            fileHandler = logging.FileHandler(
                (f"{path}/{file_name}.log"), "w"
            )

            streamHandler = logging.StreamHandler()

            fileHandler.setFormatter(formatter)
            streamHandler.setFormatter(formatter)

            logger.addHandler(fileHandler)
            logger.addHandler(streamHandler)
        return logger

我已经为上述方法编写了单元测试,如下所示:

from logger import create_Logger

os.makedirs("unit_test", exist_ok=True)


class TestCreateLogger(unittest.TestCase):
 @classmethod
    def setUpClass(cls):
        cls.logger = create_logger("unit_test", "logs")

    @classmethod
    def tearDownClass(cls):
        if os.path.isdir("unit_test"):
            shutil.rmtree("unit_test")
        else:
            raise Exception("The directory does not exist")
        del cls.logger

    def test_log_level(self):
        
        self.logger.info("First message")
        self.logger.debug("Second message")
        with open("unit_test/logs.log", "r") as fd:
            log_msg = fd.read()
        self.assertIn("First message", log_msg)
        self.assertNotIn("Second message", log_msg)

    def test_log_level_change(self):
       
        self.logger.setLevel("DEBUG")
        self.logger.info("First message")
        self.logger.debug("Second message")
        with open("unit_test/logs.log", "r") as fd:
            log_msg = fd.read()
        self.assertIn("First message", log_msg)
        self.assertIn("Second message", log_msg)

   

上面的单元测试工作正常,但我不想使用像(mkdir、rmdir 等)这样的文件操作,而是使用模拟、补丁。 由于我的方法采用两个参数(路径和文件名)并将日志消息存储到日志文件并打印到标准输出。 有人可以帮我理解如何用模拟/补丁替换开放操作吗? 目前我正在使用 mkdir 和该目录中的日志文件创建一个目录,并在测试结束时使用 tearDown 删除它们。 如何使用模拟/补丁复制相同的内容?

我建议您在这里测试的不仅仅是您自己的代码; 您正在测试FileHandler的工作是否符合记录。 测试的是create_logger创建了一个记录器,该记录器记录您打算记录的位置; FileHandler只是“where”的一种可能定义。

create_logger中唯一关心pathfile_name的是FileHandler 根本不要创建FileHandler 而是将处理程序作为参数传递,并测试您新创建的记录器是否使用它。

def create_logger(handler):
    logger = logging.getLogger()
    logger.setLevel(logging.INFO)
    formatter = logging.Formatter(
        fmt="%(asctime)s %(levelname)s %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
    )


    streamHandler = logging.StreamHandler()

    handler.setFormatter(formatter)
    streamHandler.setFormatter(formatter)

    logger.addHandler(handler)
    logger.addHandler(streamHandler)

    return logger

然后您的测试可以使用写入io.StringIO对象而不是磁盘的StreamHandler

from logger import create_Logger

os.makedirs("unit_test", exist_ok=True)


class TestCreateLogger(unittest.TestCase):
    def setUp(self):
        self.f = io.StringIO()
        self.logger = create_logger(StreamHandler(f))

    def test_log_level(self):
        self.logger.info("First message")
        self.logger.debug("Second message")
        log_msg = self.f.read()
        self.assertIn("First message", log_msg)
        self.assertNotIn("Second message", log_msg)

    def test_log_level_change(self):
        self.logger.setLevel("DEBUG")
        self.logger.info("First message")
        self.logger.debug("Second message")
        log_msg = self.f.read()
        self.assertIn("First message", log_msg)
        self.assertIn("Second message", log_msg)

在生产中,您将传递一个预制的FileHandler而不是文件路径组件。

...
foo = create_logger(FileHandler(f"{path}/{file_name}.log", "w"))

如果您担心foo是否会写入正确的文件,那是整数测试,而不是单元测试,应该写入文件系统。 这样一个要测试的函数可以是create_logger的包装器,并且是您在生产中直接使用的函数。

def create_file_logger(path, file_name):
    return create_logger(FileHandler(f"{path}/{file_name}", "w"))

(不过,该测试会简单得多,因为如果它的单元测试通过,您已经可以假设create_logger正在工作!)


请记住,记录器可以在运行时配置,因此将您将部署的记录器配置视为需要测试的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM