如何在conftest.py>Logger方法中动态获取测试用例的名称

2024-04-25 03:43:34 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在使用python、selenium和pytest框架以及页面对象模型运行测试

到目前为止,我将logger方法从BaseClass移动到conftest.py,因为如果我想记录一些东西,我必须在每个测试用例中创建一个log对象

可重复的测试用例如下:

from baseclass import BaseClass

class TestClass(BaseClass):

    def test_case1(self):
        self.log.info('testing log!')

    def test_case2(self):
        self.log.info('second log!')

我将logger方法抽象到conftest.py中,但是当我运行测试时,我在日志中得到的文件名是setup,而不是测试用例名。根据其他建议(感谢社区),我将文件名作为arg传递给logger()方法,但现在它只打印第一个测试用例名的每个日志

# Using logger(): name = inspect.stack()[0][3]
> 2021-01-27 05:42:42,377 : INFO : setup : testing log!

# Using logger(full_name), where full_name = os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]
# Similar results when using full_name = request.node.__name__ or request.module.__name__
> 2021-01-28 02:12:39,877 : INFO : test_my_page.py::TestClass::test_case1 : testing log!
> 2021-01-28 02:12:39,877 : INFO : test_my_page.py::TestClass::test_case1 : second log!

My conftest.py的设置如下:

import pytest
from selenium import webdriver
import inspect
import logging

def logger():
    log_item = logging.getLogger(name)
    with open('LogFile.log', 'w+') as logFile:
        logFile.seek(0)
        logFile.truncate()
    file_handler = logging.FileHandler("LogFile.log")
    log_format = logging.Formatter("%(asctime)s : %(levelname)s : %(name)s : %(message)s")
    file_handler.setFormatter(log_format)
    log_item.addHandler(file_handler)
    log_item.setLevel(logging.DEBUG)
    return log_item


@pytest.fixture(scope='class')
def setup(request):

    driver = webdriver.Chrome(executable_path=TestData.CHROME)
    full_name = os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]

    request.cls.log = logger(full_name)
    request.cls.driver = driver

    yield
    driver.close()

我实际上想知道正在执行的测试的名称。如下图所示:

2021-01-27 01:57:02,594 : INFO : test_my_page.py::TestClass::test_case1 : testing log! 2021-01-27 01:57:32,292 : INFO : test_my_page.py::TestClass::test_case2 : second log!

如何让logger方法在不将方法移回基类的情况下动态打印测试用例的名称? 我将要编写很多测试用例,并试图找到一种更好的方法,因为在每个测试用例中创建一个logger对象是重复的

我的基类如下:

import pytest

@pytest.mark.usefixtures('setup')
class BaseClass:
    pass

Tags: 方法namepytestimportinfologpytest
1条回答
网友
1楼 · 发布于 2024-04-25 03:43:34

以下是我的解决方案:

文件temp_test.py:使用类名将使pytest无法识别测试用例,因此我将其重命名为TestClass。您的函数名仍然是test_case1。阅读有关pytest naming convention的更多信息

from baseclass import BaseClass

class TestClass(BaseClass):

    def test_case1(self):
        # log = self.logger()
        # log.info('testing log!') # old method

        self.log.info('testing log 1!') # new method

我添加了另一个测试文件z_test.py

from baseclass import BaseClass

class Test2(BaseClass):

    def test_case2(self):
        # log = self.logger()
        # log.info('testing log!') # old method

        self.log.info('testing log 2!') # new method

    def test_case3(self):
        # log = self.logger()
        # log.info('testing log!') # old method

        self.log.info('testing log 3!') # new method

文件:conftest.py

import os
import pytest
import logging


def logger(name):
    log_item = logging.getLogger(name)
    with open('LogFile.log', 'a') as logFile:
        logFile.seek(0)
        # logFile.truncate()
    file_handler = logging.FileHandler("LogFile.log")
    log_format = logging.Formatter("%(asctime)s : %(levelname)s : %(name)s : %(message)s")
    file_handler.setFormatter(log_format)
    log_item.addHandler(file_handler)
    log_item.setLevel(logging.DEBUG)
    return log_item

@pytest.fixture(scope='function')
def setup(request):
    # full name: 'class name::function name'
    full_name = os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]
    # full_name = request.module.__name__ # print the function name
    # full_name = request.node.name # print the class name
    request.cls.log = logger(full_name)
    yield
    print('close')

conftest.py中,我修改了一些:

  • logger函数现在将具有name参数。您的测试设置将提供此名称
  • os.environ.get('PYTEST_CURRENT_TEST').split(' ')[0]将提供安装程序的全名,在这种情况下,输出将为2021-01-27 14:00:23,436 : INFO : temp_test.py::TestClass::test_case1 : testing log!
  • full_name = request.module.__name__将只提供函数名:test_case1
  • full_name = request.node.name将仅提供类名:TestClass

我认为最好使用PYTEST_CURRENT_TESTenv var,并使用它进行字符串操作


更新您对未生成其他测试名称的评论:

  • setup()需要在函数范围内,因为对于每个测试,您都希望将测试放入函数中。如果您像以前一样使用它作为class,它将只在第一个测试函数开始时调用设置程序一次。在我的示例中,它将只输出test_case2两次
  • open('LogFile.log', 'w+')应该是open('LogFile.log', 'a')。模式a将追加文本,模式w将删除所有内容,因此只保存上一个测试用例的日志
  • logFile.truncate()还将删除除最后一个测试用例日志之外的所有内容

我有:

2021-01-28 15:22:58,540 : INFO : temp_test.py::TestClass::test_case1 : testing log 1!
2021-01-28 15:22:58,543 : INFO : z_test.py::Test2::test_case2 : testing log 2!
2021-01-28 15:22:58,545 : INFO : z_test.py::Test2::test_case3 : testing log 3!

玩弄这些台词,你会得到你需要的

另一个提示:在运行测试时,您需要创建一个单独的报告文件夹,其中包含日志文件,并用日期、小时、分钟等随机命名。使用像LogFile.log这样的通用名称会导致文本追加,也许LogFile_2021_01_28_152101.log更好,由您选择

相关问题 更多 >