pytest基本应用

文章目录

  • 1.pytest安装
  • 2.用例运行规则
  • 3.常用参数
    • 断言
    • 运行参数
    • 用例控制
    • setup和teardown
    • ini配置文件
  • 4.常用插件
  • 5.pytest高阶用法
    • 用例跳过
    • 参数化
  • 6.pytest之Fixture使用
    • fixture使用
    • 装饰器usefixtures
  • 7.pytest之conftest.py
  • 8.conftest+fixture+yield
    • yield介绍
    • 前后置使用

1.pytest安装

pip install pytest

环境配置:需要设置项目的默认运行方式为unittest

image-20240219173134149

2.用例运行规则

  • pytest将在当前目录及其子目录中运行所有格式为test_*.py开头或*_test.py结尾的文件
  • 测试方法/测试函数 默认必须是test开头
  • 测试类必须是Test开头
  • 测试类不能有构造方法 __init__

示例:
image-20240219174600866

运行时可以扫描到当前目录和当前子目录下的用例:

image-20240219175351372

3.常用参数

断言

断言借助Python中的运算符号和assert关键字实现;

# -*- coding: utf-8 -*-
# @Time    : 2024/2/19 17:56
# @Author  : 居里夫人吃橘子
# @File    : test_demo03.py
# @Software: PyCharm
import pytest"""测试不相等 !=<=>=测试包含 in测试不包含 not in判断是否为true: is True判断是否不为true: is not True/is Falseandor
"""def test_demo03():print('kkkkkkk')# assert 1 == 1# assert 1 != 2# assert 1 < 2# assert 1 > 2# assert 'a' in 'abc'# assert 'a' not in 'abc'# assert True# assert False# assert 1 == 1 and 1 < 2assert 1 == 2 or 1 < 2if __name__ == '__main__':pytest.main(['-s'])

运行参数

“-s” 参数 用于关闭捕捉,从而输出打印信息到控制台

image-20240219181159678

“-v” 参数 用于显示具体的用例执行信息‘

image-20240219181223263

“-k” 运行名称中包含某字符串的测试用例,类似于模糊查找

image-20240219181253437

‘-q’ 简化输出信息

image-20240219181513726

‘-x’ 如果出现一条测试用例失败,则退出测试

image-20240219181740670

指定运行测试文件中的方法或特定的类

pytest.main([‘-s’, ‘./son_dir/test_son01.py::TestDemo01’])

image-20240220094429285

用例控制

  • 在第N个用例失败后,结束测试;
pytest.main(['-s','test_demo03.py','--maxfail=1'])

image-20240220094942836

  • 失败用例重跑

安装插件pytest-rerunfailures,注意Python版本需要>3.5;pytest>5.0

pip install pytest-rerunfailures

# '--reruns'表示重跑次数;'--reruns-delay'表示失败后间隔几秒
pytest.main(['--reruns', '3', '--reruns-delay', '1', 'test_demo03.py'])  

image-20240220104339361

  • 通过标记表达式执行指定的用例

通过@pytest.mark.标记名装饰器标记指定的测试用例,使用pytest.main(['-m', '标记名'])执行;

注:标记名需要提前注册,创建pytest.ini文件;标记名称冒号后面的为注释,最好使用英文;

[pytest]
markers =ma: marks tests as smokeslow: slow testcase
@pytest.mark.slow
def test_demo05():print('5555555555')if __name__ == '__main__':pytest.main(['-s', 'test_demo03.py', '-m', 'slow'])

image-20240220095951444

  • 多进程执行测试用例

安装插件pytest-xdist;

pip install pytest-xdist

pytest.main(['-n', 'auto', 'test_demo03.py']) #auto为自动分配与计算机相匹配的进程;也可以指定数字

image-20240220103619825

setup和teardown

  • 不含有类的用例前置和后置

1.setup_module/teardown_module: 在当前文件中,在所有测试用例执行之前与之后执行
2.setup_function/teardown_function:在每个测试函数之前与之后执行

# -*- coding: utf-8 -*-
# @Time    : 2024/2/20 10:49
# @Author  : 居里夫人吃橘子
# @File    : test_set01.py
# @Software: PyCharm# 功能函数,相乘
import pytestdef multiply(a, b):return a * b"""不含有类的用例预置和后置函数第一批次:setup_module/teardown_module: 在当前文件中,在所有测试用例执行之前与之后执行第二批次:setup_function/teardown_function:在每个测试函数之前与之后执行,不能在类中使用ps:执行的顺序按优先级来的,改变方法位置结果也一样
"""# 在当前文件前置后置
def setup_module(module):print("setup_module===================")def teardown_module(module):print("teardown_module================")# 每个用例前置后置
def setup_function(function):print("setup_function===================")def teardown_function(function):print("teardown_function================")# ========测试用例=========
def test01():print("第一个用例")print(multiply(3, 4))def test02():print("第二个用例")print(multiply(4, 4))if __name__ == '__main__':pytest.main(['-s', 'test_set01.py'])

image-20240220142300991

  • 含有类的用例前置和后置

1.setup_class/teardown_class:在当前的测试类的开始和结束时执行
2.setup_method/teardown_method:在每个测试方法开始与结束时执行
ps:执行的顺序按优先级来的,改变方法位置结果也一样

# -*- coding: utf-8 -*-
# @Time    : 2024/2/20 14:23
# @Author  : 居里夫人吃橘子
# @File    : test_set02.py
# @Software: PyCharm# 功能函数
import pytestdef multiply(a, b):return a * bclass TestCase:"""第一批次:setup_class/teardown_class:在当前的测试类的开始和结束时执行第二批次:setup_method/teardown_method:在每个测试方法开始与结束时执行ps:执行的顺序按优先级来的,改变方法位置结果也一样"""# 每个测试类前置后置@classmethoddef setup_class(cls):print("setup_class========================")@classmethoddef teardown_class(cls):print("teardown_class======================")# 每个测试方法前置后置def setup_method(self, method):print("setup_method===================")def teardown_method(self, method):print("teardown_method================")# ============测试用例============def test01(self):print("类里的第一条用例")print(multiply(2, 2))def test02(self):print("类里的第二条用例")print(multiply(4, 4))if __name__ == '__main__':pytest.main(['-s', 'test_set02.py'])

image-20240220153317481

ini配置文件

  • ini配置文件可以配置一次后运行文件默认生效,注意文件名必须为pytest.ini

pytest.ini

[pytest]
# 01 命令行参数,默认加到执行过程中
addopts = -s -v
# 02 指定要运行的测试目录
testpaths = ./son_dir
# 03 指定要运行的测试文件规则
python_files = auto_*.py
# 04 指定要运行的类名规则
python_classes = A* B*
# 05 指定要运行的测试用例方法/函数名
python_functions = ff*

image-20240220164238799

image-20240220164250253

4.常用插件

插件列表网址:https://docs.pytest.org/en/latest/reference/plugin_list.html

5.pytest高阶用法

用例跳过

  • 有条件跳过测试用例:@pytest.mark.skipif(condition=3 > 2, reason='不想执行了')
  • 无条件跳过测试用例:@pytest.mark.skip
# -*- coding: utf-8 -*-
# @Time    : 2024/2/19 17:30
# @Author  : 居里夫人吃橘子
# @File    : test_01.py
# @Software: PyCharm
import pytestdef test_demo01():print('第一条测试用例')def test_demo02():print('第二条测试用例')# 如果condition中的条件为Ture,则跳过用例
@pytest.mark.skipif(condition=3 > 2, reason='不想执行了')
def test_demo03():print('第三条测试用例')# 无条件跳过测试用例
@pytest.mark.skip(reason='不想跑了')
def test_demo04():print('第四条测试用例')if __name__ == '__main__':pytest.main(['-s', 'test_01.py'])

参数化

pytest中的参数化使用装饰器@pytest.mark.parametrize

  • 多参数化
import pytest
import math# pytest 参数化
# "base, exponent, expected"用来定义参数名,通过数组定义时,每一个元组都是一条测试用例使用的数据;ids默认为None代表用例名称
@pytest.mark.parametrize("base, exponent, expected", [(2, 2, 4), (2, 3, 8), (1, 9, 1), (0, 9, 0)],ids=["case1", "case2", "case3", "case4"])
def test_pow(base, exponent, expected):assert math.pow(base, exponent) == expectedif __name__ == '__main__':pytest.main(['-s', '-v', 'test_fuc.py'])

image-20240220165829952

  • 函数参数化
import pytestdef return_data():return [('zz', '123456'), ('xz', '123456'), ('qs', '123456')]# 把函数return_data()的值都赋给'data'上;
@pytest.mark.parametrize('data', return_data())
def test_01(data):print(data[0], data[1])if __name__ == '__main__':pytest.main(['-s', 'test_func02.py'])
  • yaml文件驱动参数化

demo01.yaml

-name : '小李'sex : '男'-name: '小王'sex: '女'
import yaml
import pytestdef pase_yaml():with open('./file/demo01.yaml', 'r', encoding='utf-8') as f:data = yaml.load(f, Loader=yaml.FullLoader)return data@pytest.mark.parametrize('data', pase_yaml())
def test_demo01(data):print(data['name'])print(data['sex'])if __name__ == '__main__':pytest.main(['-s', '-v', 'test_fuc02.py'])

输出:

image-20240220172020943

6.pytest之Fixture使用

在测试中,fixture为测试提供了已定义的,可靠的和一致的上下文。这可能包括环境(例如,通过已知的参数配置数据库)或内容(例如,数据集)。Fixtures定义了构成测试准备阶段的步骤和数据。在pytest中,它们是为这些目的而定义的函数。它们也可以用来定义测试执行阶段;这是一个设计复杂用例的强大技术。测试功能通过参数访问由fixtures设置的服务,状态或其他操作环境。对于测试功能使用的每个fixture,通常在测试功能的定义中都有一个参数(在 fixture后命名)。
我们可以通过用修饰器@pytest.fixture来告诉pytest某个特定函数是一个fixture 。

fixture使用

  • 单个fix使用
import pytest@pytest.fixture
def fix01():print('这是fix01开始运行了')print('fix01运行结束')def test_demo01(fix01):print('测试用例1')if __name__ == '__main__':pytest.main(['-s', 'test_fix_demo01.py'])

image-20240221101756912

  • 多个fix使用,并接受fix中的数据
import pytest@pytest.fixture
def fix01():print('这是fix01开始运行了')print('fix01运行结束')@pytest.fixture
def fix02():print('这是fix02开始运行了')data = ['小王', '小李']return datadef test_demo01(fix01, fix02):print('测试用例1')print(fix02[0])if __name__ == '__main__':pytest.main(['-s', 'test_fix_demo02.py'])

image-20240221102330997

  • 多个fix之间互相调用
import pytest@pytest.fixture
def first_fix():return "a"@pytest.fixture
def order(first_fix):return [first_fix]# 测试用例
def test_string(order):order.append("b")print(order)if __name__ == '__main__':pytest.main(['-s', 'test_fix_demo03.py'])

image-20240221102654055

装饰器usefixtures

说明
@pytest.mark.usefixtures是Pytest调用fixture的方法之一,与直接传入fixture不同的是,它无法获取到被fixture装饰的函数的返回值。
@pytest.mark.usefixtures的使用场景是被测试函数需要多个fixture做前后置工作时使用,个人感觉没啥大用,因为fixture也可以同时传入多个fixture

示例

import pytest@pytest.fixture
def fix01():print('这是fix01开始运行了')print('fix01运行结束')@pytest.fixture
def fix02():print('这是fix02开始运行了')data = ['小王', '小李']return data@pytest.fixture
def fix03():print('这是fix03开始运行了')print('fix03运行结束')# @pytest.mark.usefixtures('fix01', 'fix03')
# # @pytest.mark.usefixtures('fix01','fix02') # 如果使用userfixtures('fix02')则会报错,因为userfixtures无法获取fix中的返回数据
# def test_demo01():
#     print('测试用例1')@pytest.mark.usefixtures('fix03')
@pytest.mark.usefixtures('fix01')
def test_demo01():print('测试用例1')if __name__ == '__main__':pytest.main(['-s', 'test_fix_demo04.py'])

注:@pytest.mark.usefixtures('fix01', 'fix03')叠加使用时按照就近原则执行,先在前的先执行,先在下的先执行;

7.pytest之conftest.py

介绍

conftest.py是fixture函数的一个集合,可以理解为公共的提取出来放在一个文件里,然后供其它模块调用。不同于普通被调用的模块,conftest.py使用时不需要导入,Pytest会自动查找。并且支持多个py文件同时调用其中的fixture

规则

  • 文件名必须为conftest.py;
  • conftest.py文件必须与测试用例在同一个包下

示例

conftest.py文件

import pytest@pytest.fixture
def fix01():print('这是fix01开始运行了')print('fix01运行结束')

test_conftest01.py

import pytest# 测试用例
def test_conf01(fix01):print('开始运行测试用例1')if __name__ == '__main__':pytest.main(['-s', 'test_conftest01.py'])

输出:

image-20240221133639842

示例2

conftest.py文件中可以设置@pytest.fixture(scope='',autouse='')中的参数:

  • scope表示在什么时候执行:

    session:表示在所有测试文件执行前执行一次

    package:在所有包执行前执行一次

    module:在每一个py文件前执行一次

    class:在每个测试类前执行一次

    function:在每个测试用例前执行一次

  • autouse=Ture表示测试用例中不需要写fixture的名称,自动生效,默认为False

conftest.py

import pytest@pytest.fixture(scope='session', autouse=True)
def fix01():print('开始执行session')@pytest.fixture(scope='package', autouse=True)
def fix2():print('开始执行package')@pytest.fixture(scope='module', autouse=True)
def fix3():print('开始执行module')@pytest.fixture(scope='class', autouse=True)
def fix4():print('开始执行class')

test_conftest01.py

import pytest# 测试用例
def test_conf01():print('开始运行测试用例1')# 当测试用例没有在class中时,也会默认执行一次class层级的fixture
def test_conf02():print('开始运行测试用例2')class TestDemo:def test_conf03(self):print('开始运行测试用例3')if __name__ == '__main__':pytest.main(['-s', 'test_conftest01.py'])

输出:

C:\Users\11361\AppData\Local\Programs\Python\Python38\python.exe D:\PythonTest\Study\class_pytest02\test_conftest_demo01\test_conftest01.py 
============================= test session starts =============================
platform win32 -- Python 3.8.7, pytest-8.0.1, pluggy-1.4.0
rootdir: D:\PythonTest\Study\class_pytest02\test_conftest_demo01
plugins: anyio-3.6.2, dependency-0.6.0, rerunfailures-13.0, xdist-3.5.0
collected 3 itemstest_conftest01.py 开始执行session
开始执行package
开始执行module
开始执行class开始执行function
开始运行测试用例1
.开始执行class开始执行function
开始运行测试用例2
.开始执行class开始执行function
开始运行测试用例3
.============================== 3 passed in 0.05s ==============================进程已结束,退出代码0

8.conftest+fixture+yield

yield介绍

"""1.程序开始执行以后,因为test函数终有yield关键字,所以test函数并不会真正的执行,而是先得到一个生成器g2.直到调用next方法,test函数正式开始执行,先执行test函数中的print方法,然后进入while循环3.程序遇到yield关键字,然后把yield相当于是return,return了一个8之后,程序停止,并没有执行赋值给a操作,此时next(g)语句执行完成,所以输出前面两行(第一行是while上面的print的结果,第二行是return出来的结果)4.程序执行print("=====================")5.又开始执行下面的print(next(g)),这个时候是从刚才next程序停止的地方开始执行,也就是要执行a的赋值操作,这个时候因为赋值操作的右边是没有值的,已经被return出去了这个时候a的值是none,所以接下来的输出是a:none6.程序会继续在whili里执行,又一次碰到yield,这个时候同样return出8,然后程序停止。print函数输出的8就是这次return出的8
"""def test():print("begin....")while True:a = yield 8print("a:", a)g = test()
print(next(g))
print("=====================")
print(next(g))
print("=====================")
print(next(g))#输出
begin....
8
=====================
a: None
8
=====================
a: None
8

前后置使用

conftest.py

import pytest@pytest.fixture
def fix1():print('conftest里的fix1')yieldprint("用例执行完成,我来扫尾")

test_yeild01.py

import pytestdef test_case(fix1):print("测试用例一")if __name__ == '__main__':pytest.main(['-s'])

输出:

C:\Users\11361\AppData\Local\Programs\Python\Python38\python.exe D:\PythonTest\Study\class_pytest02\test_yeild_demo01\test_yeild01.py 
============================= test session starts =============================
platform win32 -- Python 3.8.7, pytest-8.0.1, pluggy-1.4.0
rootdir: D:\PythonTest\Study\class_pytest02\test_yeild_demo01
plugins: anyio-3.6.2, dependency-0.6.0, rerunfailures-13.0, xdist-3.5.0
collected 1 itemtest_yeild01.py conftest里的fix1
测试用例一
.用例执行完成,我来扫尾============================== 1 passed in 0.06s ==============================进程已结束,退出代码0

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/695549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GZ036 区块链技术应用赛项赛题第9套

2023年全国职业院校技能大赛 高职组 “区块链技术应用” 赛项赛卷&#xff08;9卷&#xff09; 任 务 书 参赛队编号&#xff1a; 背景描述 随着异地务工人员的增多&#xff0c;房屋租赁成为一个广阔是市场&#xff1b;目前&#xff0c;现有技术中的房屋租赁是由…

centos7部署nfs+keepalived+drbd

一、项目需求描述 现在使用的架构是nfskeepalivedrsyncsersync&#xff0c;目前这套架构存在主从nfs节点数据同步不一致问题&#xff0c;大概会有 120s左右的数据延长同步时间&#xff0c;需要提供优化的自动化方案。 二、现有方案缺点 1、切换不能保证主从节点数据一致。 2、…

C++之std::thread线程

std::thread是C11线程库提供的线程创建。参数绑定的是线程需要调用的函数与参数。 1、如何创建 std::thread th;//空的&#xff0c; std::thread th1([]() { //匿名函数&#xff0c; //执行线程代码 }); void thFun(int k)&#xff1b; std::thread th(thFun,10);// thFun为…

四、分类算法 - 随机森林

目录 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结 sklearn转换器和估算器KNN算法模型选择和调优朴素贝叶斯算法决策树随机森林 1、集成学习方法 2、随机森林 3、随机森林原理 4、API 5、总结

【论文阅读】【yolo系列】YOLO-Pose的论文阅读

Abstract 我们介绍YOLO-pose&#xff0c;一种无热图联合检测的新方法&#xff0c;基于流行的YOLO目标检测框架的图像二维多人姿态估计。 【现有方法的问题】现有的基于热图的两阶段方法是次优的&#xff0c;因为它们不是端到端可训练的&#xff0c;训练依赖于surrogate L1 loss…

Linux pageset

1. 引言 在用户进程发生缺页异常时&#xff0c;Linux内核需要分配所需物理页面以及建立也表映射&#xff0c;来维持进程的正常内存使用需求。而对于分配物理页面仅依赖于buddy系统&#xff0c;对于小order页面的分配效率较低。因此Linux通过在每个cpu维护一个page链表&#xff…

12 Autosar_SWS_MemoryMapping.pdf解读

AUTOSAR中MemMap_autosar memmap-CSDN博客 1、Memory Map的作用 1.1 避免RAM的浪费&#xff1a;不同类型的变量&#xff0c;为了对齐造成的空间两份&#xff1b; 1.2 特殊RAM的用途&#xff1a;比如一些变量通过位掩码来获取&#xff0c;如果map到特定RAM可以通过编译器的位掩码…

爬取链家二手房房价数据存入mongodb并进行分析

实验目的 1.使用python将爬虫数据存入mongodb&#xff1b; 2.使用python读取mongodb数据并进行可视化分析。 实验原理 MongoDB是文档数据库&#xff0c;采用BSON的结构来存储数据。在文档中可嵌套其他文档类型&#xff0c;使得MongoDB具有很强的数据描述能力。本节案例使用的…

IP地址定位可以精确到哪里

IP地址定位能够精确到的位置级别取决于多种因素&#xff0c;包括IP地址的分配方式、数据库的质量和更新频率、用户的移动性等。一般而言&#xff0c;IP地址定位可以精确到市级&#xff0c;甚至可以达到街道级别 https://www.ip66.net/?utm-sourceLJ&utm-keyword?1146 但需…

LeetCode494. Target Sum——01背包

文章目录 一、题目二、题解 一、题目 You are given an integer array nums and an integer target. You want to build an expression out of nums by adding one of the symbols ‘’ and ‘-’ before each integer in nums and then concatenate all the integers. For …

大数据在电商领域的典型应用

大数据作为一种新兴的信息技术&#xff0c;是无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合&#xff0c;是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。 大数据技术是指在数据获取、存储、管理、…

程序媛的mac修炼手册-- 如何彻底卸载Python

啊&#xff0c;前段时间因为想尝试chatgpt的API&#xff0c;需要先创建一个python虚拟环境来安装OpenAI Python library. 结果&#xff0c;不出意外的出意外了&#xff0c;安装好OpenAI Python library后&#xff0c;因为身份认证问题&#xff0c;根本就没有获取API key的权限…

Shader基础的简单实现(基于URP渲染)

一个模型是很多个顶点组成&#xff0c;顶点数据中包含坐标、法线、切线、UV坐标、顶点颜色等等组成。 URP(Universal Render Pipeline)通用渲染管线&#xff0c;是Unity在2019.3版本之后推出的一种新的渲染管线。传统的渲染管线在渲染多光源的情况&#xff0c;是把每一个主要光…

C语言第二十八弹---整数在内存中的存储

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】 目录 1、整数在内存中的存储 2、大小端字节序和字节序 2.1、什么是大小端&#xff1f; 2.2、为什么有大小端? 2.3、练习 2.3.1、练习1 2.3.2、练习2 2.…

Java 注解机制解密并发编程的时间之谜:揭开Happens-Before的神秘面纱

优质博文&#xff1a;IT-BLOG-CN 一、简介 为什么需要happens-before原则&#xff1a; 主要是因为Java内存模型 &#xff0c; 为了提高CPU效率&#xff0c;通过工作内存Cache代替了主内存。修改这个临界资源会更新work memory但并不一定立刻刷到主存中。通常JMM会将编写的代码…

Pytorch 复习总结 2

Pytorch 复习总结&#xff0c;仅供笔者使用&#xff0c;参考教材&#xff1a; 《动手学深度学习》Stanford University: Practical Machine Learning 本文主要内容为&#xff1a;Pytorch 线性神经网络。 本文以机器学习中的两大基本问题 —— 回归和分类为例&#xff0c;介绍…

【数据结构初阶 6】二叉树:堆的基本操作 + 堆排序的实现

文章目录 &#x1f308; Ⅰ 二叉树的顺序结构&#x1f308; Ⅱ 堆的概念与性质&#x1f308; Ⅲ 堆的基本操作01. 堆的定义02. 初始化堆03. 堆的销毁04. 堆的插入05. 向上调整堆06. 堆的创建07. 获取堆顶数据08. 堆的删除09. 向下调整堆10. 判断堆空 &#x1f308; Ⅳ 堆的基本…

【selenium】八大元素定位方式|xpath css id name...

目录 一、基础元素定位 二、cssSelector元素定位——通过元素属性定位 三、xpath元素定位——通过路径 1 、xpath绝对定位 &#xff08;用的不多&#xff09; 缺点&#xff1a;一旦页面结构发生变化&#xff08;比如重新设计时&#xff0c;路径少两节&#xff09;&#x…

从计网的角度讲明白什么是网关

网关(Gateway)又称网间连接器、协议转换器。网关在传输层上以实现网络互连&#xff0c;是最复杂的网络互连设备&#xff0c;仅用于两个高层协议不同的网络互连。网关的结构也和路由器类似&#xff0c;不同的是互连层。网关既可以用于广域网互连&#xff0c;也可以用于局域网互连…

JDBC实现连接池

简单上手 使用 JDBC 来执行 SQL 查询和更新操作 import java.sql.*;public class Main {public static void main(String[] args) {String url "jdbc:mysql://localhost:3306/your_database_name";String username "your_username";String password &…