• 单元测试框架pytest


    前提

    pytest是一个非官方的单元测试框架,需要先进行安装。所以pip一下

    技术点

    一、运行参数(进入到相应目录)

    1、无参数运行

    运行目录下的所有py文件:pytest
    运行目录下某一个py文件:pytest test_01.py
    运行目录下py文件中的某个类:pytest test_02.py::TestClass
    运行目录下py文件中某个类的某个方法:pytest test_02.py::TestClass::test_one
    指定目录运行:pytest testpy

    2、-v参数

    打印详细的日志信息

    3、-s参数

    代码里面有 print 输出语句,想在运行结果中打印 print 输出

    4、-k参数

    pytest -k '类名' //运行指定的类
    pytest -k '方法名' //运行指定的方法
    pytest -k '类名 and not 方法名' //运行类里的方法,不包含某个方法

    5、-x参数

    遇到失败用例立即停止运行

    6、--maxfail参数

    用例失败个数达到阀值后停止运行
    pytest --maxfail 2 test_02.py

    7、-m参数

    只运行标记 @pytest.mark.[标记名]的方法和类

    比如类名上添加:

    @pytest.mark.oneone,

    执行命令:pytest -m "oneone" test_02.py

    如果有多个标记可以用 and 或 or 进行组合

    8、--durations参数

    获取执行最慢的一个:pytest --durations=1

    9、--collect-only参数

    只收集用例不执行,可用于统计用例数

    二、pytest框架结构

     1 import pytest
     2 
     3 def setup_module():
     4     print("
    setup_module,只执行一次,当有多个测试类的时候使用")
     5 def teardown_module():
     6     print("
    teardown_module,只执行一次,当有多个测试类的时候使用")
     7 
     8 
     9 # setup_function teardown_function作用于类外的函数
    10 def setup_function():
    11     print("
    setup_function")
    12 def teardown_function():
    13     print("
    setup_function")
    14 
    15 def test_cls_out():
    16     print("类外的函数方法")
    17 
    18 
    19 class TestPytest1:
    20     def setup_class(self):
    21         print("
    setup_class1,只执行一次,当有多个测试方法的时候使用")
    22     def teardown_class(self):
    23         print("
    teardown_class1,只执行一次,当有多个测试方法的时候使用")
    24 
    25 
    26     def setup_method(self):
    27         print("
    setup_method1,每个测试方法都执行一次")
    28     def teardown_method(self):
    29         print("teardown_method1,每个测试方法都执行一次")
    30 
    31 
    32     def setup(self):
    33         print("setup")
    34     def teardown(self):
    35         print("teardown")
    36 
    37 
    38     def test_three(self):
    39         print("test_three,测试用例")
    40 
    41     def test_four(self):
    42         print("test_four,测试用例")

    三、控制执行顺序

    安装:pip install pytest-ordering
    负数越小越先执行(-100,-18,-1)
    正数越小越先执行(1,18,100)

     1 import pytest
     2 
     3 
     4 class Testpy:
     5     @pytest.mark.run(order=1)
     6     def test_one(self):
     7         print(111)
     8 
     9     @pytest.mark.run(order=18)
    10     def test_two(self):
    11         print(222)
    12 
    13     @pytest.mark.run(order=100)
    14     def test_three(self):
    15         print(333)

    四、并发执行

    安装:pip install pytest-xdist
    多个CPU并行执行用例,如果参数为 auto 自动检测系统的 CPU 数目;如果参数为数字,则指定运行测试的处理器进程数。
    pytest -n auto
    pytest -n [num]

    五、pytest-html 生成测试报告

    安装:pip install pytest-html
    指定报告的存放路径
    --html=./report/report.html
     加这个参数生成的报告css不是独立的
     --self-contained-html

    六、assert断言

    assert a
    assert a == b
    assert a in b
    assert not a
    assert a != b (a <> b一般不再使用)

    七、@pytest.fixture

    fixture 有一个参数 scope,通过 scope 可以控制 fixture 的作用范围,根据作用范围大小划分:session> module> class> function
    具体作用范围如下:
      function 函数或者方法级别都会被调用(默认)
      class 类级别调用一次
      module 模块级别调用一次
      session 是多个文件调用一次(可以跨.py文件调用,每个.py文件就是module)

    1、以参数的形式传入到方法里执行

     1 import pytest
     2 
     3 @pytest.fixture()
     4 def login():
     5     print("登录需要的操作步骤")
     6 
     7 @pytest.fixture()
     8 def operate():
     9     print("用例的执行步骤")
    10 
    11 @pytest.fixture()
    12 def xiao():
    13     print("1234567890")
    14 
    15 # 需要在函数中传入函数名,函数上需要先标记上 @pytest.fixture()
    16 def test_case1(login, operate, xiao):
    17     print("test_case1,需要登录执行完毕")

    2、fixture的两种引用方式

     1 import pytest
     2 
     3
     4 @pytest.fixture()
     5 def open():
     6     print("打开浏览器")
     7     yield
     8 
     9     print("执行teardown !")
    10     print("最后关闭浏览器")
    11 
    12 
    13 # 方式一:装饰器方式引用
    16 @pytest.mark.usefixtures("open")
    17 def test_search1():
    18     print("test_search1")
    19     # raise NameError
    20     pass
    21 
    22 
    23 # 方式二:在函数中传入
    26 def test_search2(open):
    27     print("test_search2")
    28     # raise NameError
    29     pass

    3、conftest.py应用
    conftest.py等同于scope=session
    pytest test_scope1.py test_scope2.py

    相应代码见:https://github.com/hanshoukai/pytest_fixture

    fixture为function

    fixture为class

     

     fixture为module

      fixture为session

    4、自动执行fixture装饰下的函数
    conftest.py中标记为:@pytest.fixture(autouse="true")

    每个测试函数都会自动调用该前置函数


    5、fixture传递参数

    1 import pytest
    2 
    3 @pytest.fixture(params=[1, 2, 3])
    4 def params(request):
    5     return request.param
    6 
    7 def test_com(params):
    8     print(f"测试数据:{params}")
    9     assert params < 5


    八、@pytest.mark.parametrize参数化

    传一个参数

    1 # 传一个参数
    2 @pytest.mark.parametrize("user", ["13552977251", "13552554252"])
    3 def test_user(user):
    4     print(user)

    传两个参数

    @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+5", 7), ("7*5", 35)])
    如上 "test_input,expected" 可以修改为 列表或者元组 的形式
    列表:@pytest.mark.parametrize(["test_input","expected"], [("3+5", 8), ("2+5", 7), ("7*5", 35)])
    元组:@pytest.mark.parametrize(("test_input","expected"), [("3+5", 8), ("2+5", 7), ("7*5", 35)])
    1 # 传两个参数
    2 @pytest.mark.parametrize("test_input,expected", [("3+5", 8), ("2+5", 7), ("7*5", 35)])
    3 def test_function(test_input, expected):
    4     # eval可以将字符串转成3+5的表达方式
    5     print(test_input, expected)
    6     assert eval(test_input) == expected

    传三个参数 三组数据,ids是别名必须与参数的数量保持一致

    参数组合

    1 # 参数组合
    2 @pytest.mark.parametrize("x", [1, 2])
    3 @pytest.mark.parametrize("y", [3, 4, 5])
    4 def test_num(x, y):
    5     # print(f"测试数据组合x: {x} , y:{y}")
    6     print("测试数据组合x:"+str(x)+" y:"+str(y))

    函数返回值类型

    1 # 函数返回值类型
    2 def return_data():
    3     return [(1, 2), (3, 4)]
    4 
    5 @pytest.mark.parametrize("a,b", return_data())
    6 def test_data(a, b):
    7     print(a)
    8     print(b)

    用yaml文件做为参数化的数据源

    companyid.yaml

    -
      - 23725503
      - 24721214
      - 2352987806

    data.yaml

    -
      - 20
      - 30
    -
      - 40
      - 50

    脚本:

     1 import pytest
     2 import yaml
     3 
     4 
     5 @pytest.mark.parametrize('a, b', yaml.safe_load(open("data.yaml", encoding='utf-8')))
     6 # @allure.step("方法的描述信息")
     7 def test_fo(a, b):
     8     print(a)
     9     print(b)
    10 
    11 
    12 @pytest.mark.parametrize('company_id', yaml.safe_load(open("companyid.yaml", encoding='utf-8')))
    13 # @allure.step("方法的描述信息")
    14 def test_foo(company_id):
    15     print("企业ID:", company_id)

    九、pytest.ini模板

     1 [pytest]
     2 # 空格分隔,可添加多个命令行参数  重试两次每隔5秒  生成报告
     3 addopts = -sv --reruns 2 --reruns-delay 5 --html=./report/report.html --self-contained-html
     4 #addopts = -s -v --alluredir=./result
     5 # 当前目录下
     6 testpaths = ./testcase/
     7 #配置测试搜索的文件名称,当前目录下以test开头,以.py结尾的所有文件
     8 python_files = test*.py
     9 #配置测试搜索的测试类名,当前目录下以Test开头的所有类
    10 python_classes = Test
    11 #配置测试搜索的测试类名,当前目录下以test_开头的所有方法
    12 python_functions = test_*

    十、更多插件

    用例失败后自动重新运行:pytest-rerunfailures

    使用方法:pytest test_x.py --reruns=2 --reruns-delay 5  #失败后重试2次,每次间隔5秒

    在脚本中指定定义重跑的次数,这个时候在运行的时候,就无需加上 --reruns 这个参数

    1 @pytest.mark.flaky(reruns=6, reruns_delay=2)
    2 def test_example(self):
    3     print(3)
  • 相关阅读:
    C#对List排序的三种方式的比较
    unity跨平台及热更新学习笔记-C#中通过程序域实现DLL的动态加载与卸载
    总结下C#中有关结构体的几个问题
    C#中通过逻辑^(异或)运算交换两个值隐藏的巨坑!!!
    unity实现批量删除Prefab上Miss的脚本组件
    Oracle构造列思想,decode,case,sgin,pivot四大金刚
    Oracle-计算岁数
    Oracle 集合
    Oracle 综合例子应用01
    Oracle 事实表,维表,多对多
  • 原文地址:https://www.cnblogs.com/hanxiaobei/p/13750067.html
Copyright © 2020-2023  润新知