首页 > 解决方案 > 为什么使用 pytest 参数化日志记录中的返回行,为每个参数递增?

问题描述

我写了一个 Python 代码,我正在学习如何使用 pytest 和记录我正在做的测试。我想发送一个 pytest test_ 函数将循环通过的参数列表。这是我的代码:

import pytest
import numpy as np
import logging

class TestClass:

    @pytest.fixture
    def initializeLogger(self):
        logger = logging.getLogger(__name__)
        logger.setLevel(logging.DEBUG)

        formatter = logging.Formatter('%(levelname)s:%(name)s:%(message)s')

        file_handler = logging.FileHandler(r'C:\Users\user\Data\Cross correlation\RunLog.log')
        file_handler.setFormatter(formatter)

        logger.addHandler(file_handler)
        return logger

    # Define parameters
    params = []
    params.append({'no' : 1})
    params.append({'no' : 2})
    params.append({'no' : 3})



    @pytest.mark.parametrize("params", params)
    def test_ZeroI(self, initializeLogger, params):
        logger = initializeLogger
        read = params['no']
        logger.info(f'Value inputted: {read}, Value read: {read}')
        print('success')
        assert params['no'] == read

我已经将 initializeLogger(self) 定义为一个 pytest 夹具,它在我的主要测试函数之前初始化: test_ZeroI(..) 被调用。

initializeLogger(self) 函数只是初始化记录器,然后我将它附加到为我创建文件的 file_handler。然后我返回记录器。

我创建了一个名为 params 的列表,并添加了带有键“no”的字典值以及我想要遍历的值;所以在这种情况下:1、2、3。

那么 testZeroI() 函数(根据我的理解)应该运行 3 次,分别按顺序依次使用参数 1、2 和 3。我添加了以下行: logger.info(f'Value input: {read}, Value read: {read}') 它只是读取值并输出到日志中。

但是,问题出在日志中,这是我看到的:

INFO:module2:Value input: 1, Value read: 1 INFO:module2:Value input: 2, Value read: 2 INFO:module2:Value input: 2, Value read: 2 INFO:module2:Value input: 3, Value read : 3 INFO:module2:Value input: 3, Value read: 3 INFO:module2:Value input: 3, Value read: 3

如您所见,值 1 被记录一次。值 2 被记录两次。值 3 记录了 3 次。我在我的代码中做错了什么?我的目的是让我的代码输出这样的日志:

INFO:module2:Value input: 1, Value read: 1 INFO:module2:Value input: 2, Value read: 2 INFO:module2:Value input: 3, Value read: 3

标签: pythonloggingpytest

解决方案


在您的夹具中initializeLogger,您logger.addHandler(file_handler)每次都在同一个记录器上调用,因此每次使用夹具时您都会获得一个额外的记录器。

您可以确保只调用一次代码(例如使用单例,或将其放入类设置中),或者在使用后删除记录器。
如果使用夹具,您可以执行以下操作:

@pytest.fixture
def get_logger():
    logger = logging.getLogger(__name__)
    ...
    logger.addHandler(file_handler)
    yield logger
    logger.handlers.clear()

或者你可以使用setup/teardown来做同样的事情:

class TestClass:

   def setup_method(self):
        self.logger = logging.getLogger(__name__)
        ...
        self.logger.addHandler(file_handler)

   def teardown_method(self):
       self.logger.handlers.clear()

如果您想在整个测试中使用相同的处理程序,您可以使用类初始化器:

class TestClass:
   logger = None

   @classmethod
   def setup_class(cls):
       cls.logger = initializeLogger()

   @classmethod
   def teardown_class(cls):
       cls.logger.handlers.clear()

推荐阅读