Pytest基础

ops/2024/10/18 14:18:22/

1.用例的设计原则

用Pytest写用例时候,一定要按照下面的规则去写,否则不符合规则的测试用例是不会执行的
1、文件名以 test_.py 文件和test.py
2、以 test
开头的函数
3、以 Test 开头的类,不能包含__init__方法
4、以 test_ 开头的类里面的方法
5、所有的包 pakege 必须要有__init__.py 文件

2.pycharm执行用例配置

在这里插入图片描述

pytest_10">3.常用pytest执行用例命令

1.查看pytest命令行参数,可以用pytest -h 或pytest --help
2.执行当前文件夹下面的所有文件

pytest 文件名/

3.执行具体的某一测试文件

pytest 脚本名称.py

4.-k 匹配用例名称
执行测试用例名称包含qq的所有用例:

pytest -k qq test_1.py

根据用例名称排除某些用例

pytest -k "not qq" test_1.py

同时匹配不同的用例名称

pytest -k "wechat or webo" test_1.py

5.按节点运行
每个收集的测试都分配了一个唯一的nodeid,它由模块文件名和 :: 组成 来自参数化的类名,函数名和参数,由:: characters分隔
运行.py模块里面的某个函数:

pytest test_mod.py::test_func

运行.py模块里面,测试类里面的某个方法

pytest test_mod.py::TestClass::test_method

6.-x 遇到错误时停止测试

pytest -x test_class.py

7.–maxfail=num 当用例错误个数达到指定数量时,停止测试

pytest --maxfail=1

8.-q 简单打印,只打印测试用例的执行结果

pytest -q test_1.py

9.-s 详细打印,-v 更加详细的打印,通过的.用pass表示

pytest -s test_1.py
pytest -v test_1.py

4.用例执行状态

用例执行完成后,每条用例都有自己的状态,常见的状态有:
passed:测试通过
failed:断言失败
error:用例本身写的质量不行,本身代码报错(譬如:fixture不存在,fixture里面有报错)
xfail:预期失败,加了 @pytest.mark.xfail()

5.常用断言

pytest 里面断言实际上就是 python 里面的 assert 断言方法,常用的有以下几种:
assert xx :判断 xx 为真
assert not xx :判断 xx 不为真
assert a in b :判断 b 包含 a
assert a == b :判断 a 等于 b
assert a != b :判断 a 不等于 b

6.setup和teardown

按照范围的不同,一共有以下十种:

  • 模块级别:setup_module、teardown_module
    setup_module:在每个模块执行前执行
    teardown_module:在每个模块执行后执行
    有几个模块就有几对
  • 函数级别:setup_function、teardown_function,不在类中的方法
    setup_function:在每个函数执行前执行
    teardown_function:在每个函数执行后执行
    有几个函数就有几对
  • 类级别:setup_class、teardown_class
    setup_class:在每个类执行前执行
    teardown_class:在每个类执行后执行
    有几个类就有几对
  • 方法级别:setup_method、teardown_method
    setup_method:在类里面的每个方法执行前执行
    teardown_method:在类里面每个方法执行后执行
  • 方法细化级别:setup、teardown
    跟上面的方法级别的含义一致,两种写法都可以

注意:函数级别和方法级别的区别在于:函数级别的前置后置是针对不在类中的方法,而不是测试用例

7.跳过测试用例

pytestmarkskip_111">7.1 @pytest.mark.skip

跳过执行测试用例,有可选参数reason:跳过的原因,会在执行结果中打印

@pytest.mark.skip
def test_wechat():
print('此测试用例不会被执行')

pytestmarkskipifcondition_reason_119">7.1 @pytest.mark.skipif(condition, reason=“”)

作用:希望有条件地跳过某些测试用例
注意:condition需要返回True才会跳过

@pytest.mark.skipif(sys.platform == 'win32', reason="does not run on windows")
def test_function(self):
print("不能在window上运行")

8.参数化

8.1语法

@pytest.mark.parametrize(argnames, argvalues, indirect=False, ids=None, scope=None)
1.argnames
含义:参数名字
格式:字符串"arg1,arg2,arg3"【需要用逗号分隔】
2.argvalues
含义:参数值列表
格式:必须是列表,如:[ val1,val2,val3 ]
如果只有一个参数,里面则是值的列表
@pytest.mark.parametrize(“username”, [“yy”, “yy2”,“yy3”])
如果有多个参数例,则需要用元组来存放值,一个元组对应一组参数的值,如:
@pytest.mark.parametrize(“name,pwd”, [(“yy1”, “123”), (“yy2”, “123”), (“yy3”, “123”)]),
也可以用字典保存
@pytest.mark.parametrize(“name,pwd”,[{‘name’:‘yy1’,‘pwd’:‘123’},
{‘name’:‘yy2’,‘pwd’:‘123’},{‘name’:‘yy3’,‘pwd’:‘123’}])
3.ids
含义:用例的ID
格式:传一个列表,[“”,“”,“”]
作用:可以标识每一个测试用例,自定义测试数据结果的显示,为了增加可读性
强调:ids的长度需要与测试数据列表的长度一致
场景:只有测试数据和期望结果不一样,但操作步骤是一样的测试用例可以用上参数化;
示例:

#未参数化
def test_1():
assert 3 + 5 == 9
def test_2():
assert 2 + 4 == 6
def test_3():
assert 6 * 9 == 42
#参数化
@pytest.mark.parametrize("test_input,expected", [("3+5", 8),("2+4", 6), ("6*9",42)])
def test_eval(test_input, expected):
print(f"测试数据{test_input},期望结果{expected}")
assert eval(test_input) == expected

8.2 参数化之数据格式

1.[(),(),()…] 列表嵌套元组

@pytest.mark.parametrize("test_input,expected", [("3+5", 8),("2+4", 6), ("6*9",42)])
def test_eval(test_input, expected):
print(f"测试数据{test_input},期望结果{expected}")
assert eval(test_input) == expected

在这里插入图片描述

2.[{},{},{}…] 列表嵌套字典

data = [
{'test_input':"3+5",'expected':8},
{'test_input':"6+5",'expected':11},
{'test_input':"3*5",'expected':15},
]
@pytest.mark.parametrize('dic',data)
def test_eval(dic):
assert eval(dic['test_input']) == dic['expected']

在这里插入图片描述

只有一条用例,但是利用参数化输入三组不同的测试数据和期望结果,最终执行的测试用例数=3,可以节省很多代码

8.3参数化之“笛卡尔积”

# 笛卡尔积,组合数据
data_1 = [1, 2, 3]
data_2 = ['x', 'y']
@pytest.mark.parametrize('a', data_1)
@pytest.mark.parametrize('b', data_2)
def test_parametrize_1(a, b):
print(f'笛卡尔积 测试数据为 : {a}{b}')

运行结果如下:
在这里插入图片描述
备注
一个函数或一个类可以装饰多个 @pytest.mark.parametrize,最终生成的用例数是nm,比如上面的代码就是:参数a的数据有3个,参数b的数据有2个,所以最终的用例数有32=6条。当参数化装饰器有很多个的时候,用例数都等于nnnn

8.4参数化之标记数据

# 标记参数化
@pytest.mark.parametrize("test_input,expected", [
("3+5", 8),
("2+4", 6),
pytest.param("6*9", 42, marks=pytest.mark.xfail),# 预期失败
pytest.param("6*6", 42, marks=pytest.mark.skip) # 跳过
])
def test_mark(test_input, expected):
assert eval(test_input) == expected

运行结果如下:
在这里插入图片描述

8.5参数化之增加可读性

ids传递的数据:

import pytest
data = [
{'test_input':"3+5",'expected':8},
{'test_input':"6+5",'expected':11},
{'test_input':"3*5",'expected':15},
]
ids = [f"test_input的值是{dic['test_input']},expected的值是{dic['expected']}"for
dic in data]
@pytest.mark.parametrize('dic',data,ids=ids)
def test_eval(dic):
assert eval(dic['test_input']) == dic['expected']

9.conftest.py

conftest.py配置fixture注意事项
pytest会默认读取conftest.py里面的所有fixture。conftest.py 文件名称是固定的,不能改动
不同目录可以有自己的conftest.py,一个项目中可以有多个conftest.py。测试用例文件中不需要手动import conftest.py,pytest会自动查找

10. fixture

10.1 fixture的优势

  • 命名方式灵活,不局限于 setup 和teardown 这几个命名
  • conftest.py 配置里可以实现数据共享,不需要 import 就能自动找到fixture
  • scope=“module” 可以实现多个.py 跨文件共享前置
  • scope=“session” 以实现多个.py 跨文件使用一个 session 来完成多个用例
  • 如果fixture使用了yield返回值,则不能在用例中显示调用fixture

10.2定义

语法:

@pytest.fixture(scope="function", params=None, autouse=False, ids=None,
name=None)
def fixture_name():
print("fixture初始化的参数列表")

参数含义:
scope:可以理解成fixture的作用域,默认:function,还有class、module、package、session
四个【常用】
function(默认):每个测试函数都会得到一个新的 fixture 实例。这是最常见的用法,适用于大多数情况。
class:每个测试类会得到一个新的 fixture 实例,该实例在类中的所有测试方法之间共享。这在你需要在类的多个测试方法之间共享状态时非常有用。
module:整个测试模块只创建一个 fixture 实例,并在该模块的所有测试函数之间共享。这适用于模块级别的设置和清理。
session:整个测试会话只创建一个 fixture 实例,并在所有测试模块和函数之间共享。这通常用于设置和清理那些非常昂贵或耗时的资源,如数据库连接。
package:在一个包中,该fixture只会被执行一次
autouse:默认:False,需要用例手动调用该fixture;如果是True,所有作用域内的测试用例都
会自动调用该fixture
name:默认:装饰器的名称,同一模块的fixture相互调用建议写个不同的name

10.3调用

调用方法:
只需要在引用fixture函数的测试用例里面传入被@pytest.fixture这个装饰器装饰的函数的名字即可,就
会调用fixture函数中定义的功能,用yield关键字去划分是setup还是teardown,yield前面实现的功能是
setup初始化功能,yield后面实现的功能是teardown清场功能。


http://www.ppmy.cn/ops/21119.html

相关文章

C++中布隆过滤器

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…

Pandas 2.2 中文官方教程和指南(十七)

原文:pandas.pydata.org/docs/ 重复标签 原文:pandas.pydata.org/docs/user_guide/duplicates.html Index对象不需要是唯一的;你可以有重复的行或列标签。这一点可能一开始会有点困惑。如果你熟悉 SQL,你会知道行标签类似于表上的…

pikachu-xss

反射型xss(get) 1.字数限制 按原本的做法,应该先写一个script标签测试一下,但是发现有字符限制。 2.解决方法 这里有两个可以插入的地方,一个是submit的提交框,另一个是url地址栏 submit:修…

GEE案例——1990-2023年计算某个区域的NDVI时序变化轨迹(以徐州市为例)

简介 我们在长时间序列的分析中,往往会根据影像时序的长短来进行分析,这里我们以NDVI指数进行长时序分析,来实现NDVI1990-2023年长时序的监测。 时序监测 时序监测是指通过对连续时间序列的遥感图像进行分析,以观察和监测地表特征、植被生长、环境变化等的动态变化过程。…

Ubuntu设置jar包开机自启(亲测有效)

1、在/etc/init.d/下新建一个脚本 cmis-admin.sh 2、在脚本中进行编辑 #!/bin/sh ### BEGIN INIT INFO # Provides: cmis-admin.sh # Required-start: $local_fs $remote_fs $network $syslog # Required-Stop: $local_fs $remote_fs $network $syslog # Defa…

堆的介绍,实现(c语言实现)

目录 堆的概念 堆的性质: 堆的分类 父子结点的下标关系 堆的向下调整算法 ​编辑小堆 大堆 建堆 堆的向上调整算法 小堆 大堆 堆的基本操作 定义堆 初始化堆 销毁堆 打印堆 堆的插入 堆的删除 大堆(Max Heap)的向下调整算法…

javaEE初阶——多线程(九)——JUC常见的类以及线程安全的集合类

T04BF 👋专栏: 算法|JAVA|MySQL|C语言 🫵 小比特 大梦想 此篇文章与大家分享多线程专题的最后一篇文章:关于JUC常见的类以及线程安全的集合类 如果有不足的或者错误的请您指出! 目录 3.JUC(java.util.concurrent)常见的类3.1Callable接口3.2 RentrantLoc…

SpringBoot + Dubbo + zookeeper实现

目录 一,框架搭建 1. 启动zookeeper ! 2. IDEA创建一个空项目; 3.创建一个模块,实现服务提供者:provider-server , 选择web依赖即可 4.项目创建完毕,我们写一个服务,比如卖票的服…