自动化测试框架设计-04开发pytest插件

摘要: 在上一篇文章中我们介绍了4个python单元测试框架,本章我们介绍如何开发pytest插件。

本章我们介绍如何开发pytest插件,在上一篇文章中我们介绍了4个python单元测试框架。大概分两类,一类是必须有类继承的,例如 QTAF  和 unittest , 另一类是可以没有类继承,例如nose/nose2  和 pytest 。对于没有可以没有类继承的框架,开发难度会稍大一些。

pytest扩展能力

如果我们需要给pytest增加额外的扩展能力,那么有三种方式。

1. 钩子函数

利用conftest.py  这个特殊的问题,可以创建钩子函数。

  • 目录结构:
pytest_sample/
├── conftest.py
└── test_sample.py 
    

conftest.py 文件中实现如下功能。


        import pytest 
        @pytest.fixture 
        
        def 
        hello
        ():     
        return 
        "hello 虫师" 
    

定义一个函数hello() ,并使用pytest.fixture 装饰器对其进行装饰。fixture的概念我们前面已经做介绍。这里fixture  默认的级别为function ,可以理解为被装饰的函数会在每个功能前被执行。

然后,在test_sample.py  测试文件中调动钩子函数。


        # 调用钩子函数hello 
        
        def 
        test_case
        (hello):     print(
        "hello:", hello)
    
        assert hello == 
        "hello 虫师" 
    

在测试用例中钩子函数hello() 作为测试用例的参数hello  被调用了。断言 hello 函数返回的结果是否为“hello 虫师”

  • 执行用例:

      >
       pytest -vs test_sample.py ================================= test session starts ===========================
collected 1 item
test_sample.py::test_case hello: hello 虫师
PASSED
================================== 1 passed in 2.61s ============================= 
  

2. 用例装饰器

我们比较常用的用例装饰是parametrize ,用法如下。


      import pytest 
      @pytest.mark.parametrize(     
      'a, b', 
    [
        (
      12),
        (
      23),
        (
      34),
    ]
) 
      
      def 
      test_add
      (a, b):     print(
      f'a:
      {a}, b:
      {b}')
    
      assert a + 
      1 == b 
  

使用pytest.mark.parametrize() 装饰器,装饰test_add() 测试用例。定义a和b为参数变量,每次取一组数据进行测试。

  • 运行结果

    >
     pytest -vs test_sample.py ================================= test session starts ===========================
collected 3 items
test_sample.py::test_add[1-2] a:1, b:2
PASSED
test_sample.py::test_add[2-3] a:2, b:3
PASSED
test_sample.py::test_add[3-4] a:3, b:4
PASSED
================================== 3 passed in 2.51s ============================= 

3.命令行参数

通过pytest  命令执行用例的时候作为参数传值。以pytest 的扩展插件pytest-base-url  为例。

  • 安装

  >
   pip install pytest-base-url 

编写用例如下:

def  test_example (base_url):

    print( "base_url:", base_url)

     assert  "http"  in base_url

这里同样用到了钩子函数base_url , 但base_url的参数定义是在执行用例的时候作为参数传入的。

  • 运行测试

>
 pytest -vs test_sample.py --base-url https://www.baidu.com ================================= test session starts ===========================
collected 1 item
test_sample.py::test_example base_url: https://www.baidu.com
PASSED
================================== 1 passed in 2.51s ============================= 

pytest扩展插件

实现pytest-hello插件

我么暂且称这个插件为pytest-hello

创建pytest_hello.py 文件,实现代码如下:

import pytest



from typing  import Any, Optional







def  pytest_configure (config: Any) ->  None:


     """      register an additional marker

    """

    config.addinivalue_line(











          "markers""env(name): mark test to run only on named environment"



    )

def  pytest_runtest_setup (item: Any) ->  None:


    """


    Called to perform the setup phase for a test item.

    """

    env_names = [mark.args[ 0for mark  in item.iter_markers(name= "env")]

     if env_names:

         if item.config.getoption( "--env"not  in env_names:

            pytest.skip( "test requires env in {!r}".format(env_names))

@pytest.fixture(scope="function")

def  hello (hello_name: str) -> str:

    """

    hello Hook function

    """



     return  f"hello,  {hello_name}"

@pytest.fixture(scope="function") def  hello_name (pytestconfig: Any) -> Optional[str]:


    """

    hello_name Hook function




    """     names = pytestconfig.getoption( "--hello" )

     if len(names) ==  0:

         return  "虫师"

     if len(names) ==  1:

         return names[ 0]

     return names[ 0]







def  pytest_addoption (parser: Any) ->  None:

"""

上一篇