当前位置:   article > 正文

自动化测试基础——Pytest测试框架

pytest

前言

Pytest是一个成熟的全功能的Python测试工具

一、Pytest测试框架介绍


Pytest是一个成熟的全功能的Python测试工具

  • 简单灵活易上手

  • 支持参数化

  • 支持简单的单元测试和复杂的功能测试,还可以用来做自动化测试

  • 具有很多第三方插件,并且可以自定义扩展

  • 测试用例的skip和xfail处理

  • 可以很好的和Jenkins集成

  • 支持运行由Nose、UnitTest编写的测试用例

  • pytest主要做什么

    • 1.执行测试用例
    • 2.通过断言判断测试结果
    • 3.生成测试报告

二、Pytest测试框架安装及常用插件

1.Pytest框架独立安装

  • Pytest框架安装

    pip install pytest
    
    • 1

    在这里插入图片描述

  • 查看Pytest安装版本

    pytest --version
    
    • 1

    在这里插入图片描述

2.通过.txt文件批量安装

  • requirements.txt文件:用于存放需要安装的第三方库的名称(requirements.txt文件名可以自定义)

  • 安装 requirements.txt 文件内指定的第三方库:

    pip install -r requirements.txt
    
    • 1

在这里插入图片描述

3.Pytest常用的插件


有的插件,安装之后,自动启用。有的插件,安装之后,配置后才启用

  • pytest:pytest测试框架本身
  • pytest-html:生成html报告(–html 参数的使用)
  • pytest-xdist:多线程,并发执行用例,并发意味着无序(-n 参数的使用需要用到此插件)
  • pytest-ordering:控制用例的执行顺序(与 pytest-order 插件效果一致)
  • pytest-order:控制用例的执行顺序(与 pytest-ordering 插件效果一致)
  • pytest-rerunfailures:失败用例重跑(–reruns 参数的使用需要用到此插件)
  • pytest-base-url:处理基础路径(测试环境、开发环境、预发布环境、生产环境)
  • pytest-result-log:将用例的名称和结果,保存到日志文件
  • allure-pytest:生成allure报告
  • requests:requests是一个简洁且简单的处理HTTP请求的第三方库(实现接口自动化)

pytest-yaml-sanmu
pyyaml
jsonpath

三、Pytest测试框架默认规则

  1. 会遍历所有的目录(特殊目录除外,比如venv文件)
  2. 寻找test_开头或_test结尾的python文件
  3. 寻找Test开头并且没有__init__方法的类,从类中按照函数的要求寻找方法
  4. 寻找test开头的函数(1.不能有参数 2.不能拥有返回值)

四、Pytest测试框架运行方式

1.命令行运行

  • 命令行使用pytest运行

    pytest
    
    • 1

    在这里插入图片描述

2.主函数运行

  • 项目根目录下任意创建一个python文件,编写如下代码,然后运行

    import pytest
    
    if __name__ == '__main__':
        pytest.main()
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

3.通过pytest.ini全局配置文件运行


查看本文的第五大标题(最常用,也是用的最多的)

4.启动参数

在这里插入图片描述

五、Pytest测试框架中的pytest.ini全局配置文件

  • 1.pytest.ini是Pytest的全局配置文件,一般放在项目的根目录下

  • 2.是一个固定的文件,文件名必须为pytest.ini

  • 3.pytest.ini全局配置文件可以改变Pytest的运行方式,设置配置信息,读取后按照配置的内容去运行

  • pytest.ini 全局配置文件常用内容如下

    # pytest.ini是pytest框架的一个全局配置文件
    # [pytest]必须带有
    [pytest]
    
    # addopts:默认执行pytest参数设置
    # -v:用于显示每个测试函数的执行结果
    # -s:用于显示测试函数中print()函数输出
    # -x:只要有一个用例执行失败就停止当前线程的测试执行
    # -k=value:用例包含value值则用例被执行(value可以修改为任意值)
    # -n=2:多线程或分布式运行测试用例,2个线程执行测试用例,减少测试用例执行的时间
    # -m=smoke:执行被 @pytest.mark.smoke 标记的用例
    # --maxfail=2:有两个用例执行失败就停止当前线程的测试执行
    # --reruns=2:失败用例重跑2次
    # --html=path:生成HTML测试报告,path代表生成报告存放文件的路径
    # addopts = -vsx -n=2 -k=login -m=smoke --maxfail=2
    
    addopts = -vs --html=./report/report.html
    
    # 执行的测试用例的的路径
    testpaths = ./testcase
    
    # 配置匹配执行的文件名称
    python_files = test_*.py
    
    # 配置匹配类名称
    python_classes = Test*
    
    # 配置匹配测试用例方法的规则
    python_functions = test_*
    
    # 声明标记
    markers =
        smoke:冒烟测试用例
        usermanager:用户管理模块
        productmanager:商品管理模块
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
参数作用
-v(verbose)显示详细信息:执行的用例、结果、进度、用例个数、执行时间
-s用于显示测试函数中print()函数输出
-n=num启用多线程或分布式运行测试用例。需要安装 pytest-xdist 插件模块(num代表开启的线程数)
–reruns=num失败用例重跑num次。需要安装 pytest-rerunfailures 插件模块。
-x只要有一个用例执行失败就停止当前线程的测试执行
–maxfail=num只要有num个用例执行失败就停止当前线程的测试执行,与-x功能一样,只是用例失败次数可自定义(–maxfail=2)
-k=value用例包含value值则用例被执行(-k=login,执行包含有login的用例,-k=login or register)
-m=标签名执行被 @pytest.mark.标签名 标记的用例 (-m=smoke or usermanager)
–reruns=num失败用例重跑num次,需要安装 pytest-rerunfailures 插件模块
–html=path生成HTML测试报告,path代表生成报告存放的路径,需要安装 pytest-html 插件模块(--html=./report/report.html)

-m 参数的使用

在这里插入图片描述

六、使用Pytest测试框架编写用例

  • pytest默认规则
    • 1.模块名必须以test_开头或_test结尾的python文件
    • 2.测试类必须以Test开头并且没有__init__方法
    • 3.测试用例方法必须以test开头

在这里插入图片描述

七、Pytest跳过测试用例

  • 无条件跳过

    @pytest.mark.skip(reason="无条件直接跳过")
    def test_add(self):
    	print("这是添加数据用例")
    
    • 1
    • 2
    • 3

    在这里插入图片描述

  • 有条件跳过

    age = 17
    
    @pytest.mark.skipif(age < 18, reason="年龄小于18跳过")
    def test_register(self):
    	print("这是注册测试用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

八、Pytest测试用例的前后置


一般现在下面的方法使用的都比较少,一般都是使用Fixture实现

1.用例前后置

  • setup_method:前置-用例执行之前

  • teardown_method:后置-用例执行之后

    # 前置-用例执行之前
    def setup_method(self):
        print("用例之前执行的代码")
    
    # 后置-用例执行之后
    def teardown_method(self):
        print("用例之后执行的代码")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

注意:随着Pytest的版本更新可能会无法使用,这里使用的是Pytest 7.4.4 版本进行演示的

2.类前后置

  • setup_class:类之前

  • teardown_class:类之后

    # 类之前
    def setup_class(self):
        print("类之前执行")
    
    # 类之后
    def teardown_class(self):
        print("类之后执行")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

注意:随着Pytest的版本更新可能会无法使用,这里使用的是Pytest 7.4.4 版本进行演示的

九、Pytest测试用例的前后置固件Fixture(固件,夹具)

1.Fixture装饰器

@pytest.fixture(scope="作用范围", autouse=True/False,params="参数化",ids="参数别名",name="Fixture别名")
  • 1
  • scope:作用域(function、class、module、package、session)
  • autouse:自动还是手动(True代表自动,False代表手动)
  • params:参数化
  • ids:参数化别名(不重要,不能单独使用,必须和 params 一起使用,因为它的作用是参数别名)
  • name:Fixture别名(一旦使用别名,则原来的名称不能再使用了)

2.Fixture的作用范围


Fixture支持5级作用域,让用例共享Fixture

  • function:每个用例不共享Fixture的返回值,默认
  • class:每个类中的用例,共享Fixture
  • module:每个模块(文件)中的用例,共享Fixture
  • package:每个包(目录)中的用例,共享Fixture
  • session:所有的用例,共享Fixture

3.Fixture的使用

  • 函数自动调用

    import pytest
    
    
    # autouse=True代表自动调用,autouse=False代表手动调用
    @pytest.fixture(scope="function", autouse=True)
    def connection_sql():
        print("用例执行前连接数据库")
        yield
        print("用例执行后关闭数据库")
    
    
    class TestFirstClass():
    
        def test_login(self):
            print("这是登陆测试用例")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

  • 函数手动调用

    import pytest
    
    
    # autouse=True代表自动调用,autouse=False代表手动调用
    @pytest.fixture(scope="function", autouse=False)
    def connection_sql():
        print("用例执行前连接数据库")
        yield
        print("用例执行后关闭数据库")
    
    
    class TestFirstClass():
    
        def test_login(self, connection_sql):
            print("这是登陆测试用例")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

  • 类自动调用

    import pytest
    
    
    @pytest.fixture(scope="class", autouse=True)
    def connection_sql():
        print("用例执行前连接数据库")
        yield
        print("用例执行后关闭数据库")
    
    
    class TestFirstClass1():
    
        def test_login(self):
            print("这是登陆测试用例")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    
    class TestFirstClass2():
    
        def test_delete(self):
            print("这是删除测试用例")
    
        def test_update(self):
            print("这是修改测试用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述

  • 类手动调用

    import pytest
    
    
    @pytest.fixture(scope="class", autouse=False)
    def connection_sql():
        print("用例执行前连接数据库")
        yield
        print("用例执行后关闭数据库")
    
    
    @pytest.mark.usefixtures("connection_sql")
    class TestFirstClass1():
    
        def test_login(self):
            print("这是登陆测试用例")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    
    class TestFirstClass2():
    
        def test_delete(self):
            print("这是删除测试用例")
    
        def test_update(self):
            print("这是修改测试用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

functionclass 作用域的Fixture手动使用的会比较多,modulepackagesession 级别的Fixture一般都是自动

4.Fixture中的params参数化(了解即可)

@pytest.fixture(scope="作用范围", autouse=True/False,params="参数化",ids="参数别名",name="Fixture别名")
  • 1
  • params:参数化,根据提供的数据组数来决定用例的执行次数。参数值可以是list或tuple

    import pytest
    
    
    @pytest.fixture(scope="function", autouse=False, params=["张三", "李四", "王五"])
    def connection_sql(request):
        print("用例执行前连接数据库")
        yield request.param
        print("用例执行后关闭数据库")
    
    
    class TestFirstClass():
    
        def test_login(self, connection_sql):
            print(f"这是登陆测试用例—— {connection_sql}")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    在这里插入图片描述

十、Pytest测试用例的前后置固件Fixture结合conftest.py文件一起使用

  • conftest.py 文件是专门用来存放Fixture固件的(文件名是固定的,不可变)
  • conftest.py 文件内的固件在使用时都不需要导包。默认同级或子级的 python 文件都可以使用
  • conftest.py 文件可以有多个,作用域都是 同级或子级
  • conftest.py 同样的调用方式,都是自动调用的情况下,外层的优先级高于内层。都是手动调用的情况下,先调用的优先级高于后调用的

在这里插入图片描述

十一、Pytest测试框架的执行过程

Pytest的调用流程如下:

  1. pytest程序启动时,会先加载命令行参数和配置文件
  2. pytest会根据命令行参数和配置文件中指定的测试文件或目录,找到所有的测试模块和测试函数
  3. pytest会对找到的测试模块和测试函数进行收集和解析,生成测试用例
  4. pytest会根据测试用例生成测试执行计划,确定测试的顺序和依赖关系
  5. pytest会按照测试执行计划,依次执行每个测试用例
  6. pytest会捕获测试用例的执行结果,并生成测试报告
  7. pytest会根据配置文件中的设置,执行相应的测试结果处理操作,如生成HTML报告、发送邮件等
  8. 执行完所有的测试用例后,pytest会输出测试结果统计信息,并退出程序

十二、Pytest测试框架控制测试用例的执行顺序


Pytest默认是从上往下执行测试用例

1.方法一:使用pytest-ordering插件

  1. 安装 pytest-ordering 插件

    pip install pytest-ordering
    
    • 1
  2. 使用 @pytest.mark.run(order=number) 进行标记(number数字越小,优先执行级别越高)

    import pytest
    
    
    class TestFirstClass():
    
        def test_login(self):
            print("这是登陆测试用例")
    
        @pytest.mark.run(order=1)
        def test_register(self):
            print("这是注册测试用例")
    
        @pytest.mark.run(order=2)
        def test_add(self):
            print("这是添加数据用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

2.方法二:使用pytest-order插件

  1. 安装 pytest-order 插件

    pip install pytest-order
    
    • 1
  2. 使用 @pytest.mark.order(number) 进行标记(number数字越小,优先执行级别越高)

    import pytest
    
    
    class TestFirstClass():
    
        def test_login(self):
            print("这是登陆测试用例")
    
        @pytest.mark.order(1)
        def test_register(self):
            print("这是注册测试用例")
    
        @pytest.mark.order(2)
        def test_add(self):
            print("这是添加数据用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

十三、Pytest测试框架的基础路径设置

  • 使用 pytest-base-url 处理基础路径(测试环境、开发环境、预发布环境、生产环境)

  • 在测试用例中可以当成是fixtrue手动调用

    1.安装 pytest-base-url 插件

    pip install pytest-base-url
    
    • 1

    2.基础路径设置

    pytest.in全局配置文件

    # 基础路径(开发、测试、预发布、生产)
    base_url = ip地址/端口号
    
    • 1
    • 2
    import pytest
    
    
    class TestFirstClass():
    
        def test_login(self,base_url):
            print(f"这是登陆测试用例 {base_url}")
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    在这里插入图片描述

十四、Pytest测试框架断言

  • Pytest中断言使用的是Python里面的原生的 assert 断言

  • 断言正确则用例执行会通过,断言失败,用例执行会不通过

    class TestFirstClass():
    
        def test_login(self):
            print("这是登陆测试用例")
            # 断言实际结果是否包含了 "希望" 两个字
            assert "希望" in "今天又是充满希望的一天"
    
        def test_register(self):
            print("这是注册测试用例")
    
        def test_add(self):
            print("这是添加数据用例")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述

十五、Pytest测试框架的parametrize简单数据驱动

  • 使用 @pytest.mark.parametrize("参数名", 参数值(可以是list或tuple)) 实现数据驱动

    import pytest
    
    
    class TestFirstClass():
    
        @pytest.mark.parametrize("name,age", [["张三", 18], ["李四", 28], ["王五", 20]])
        def test_query(self, name, age):
            print(name, age)
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号