Pytest基础

1.用例的设计原则

用Pytest写用例时候,一定要按照下面的规则去写,否则不符合规则的测试用例是不会执行的

1、文件名以 test_.py 文件和 test.py
2、以 test
开头的函数

3、以 Test 开头的类,不能包含__init__方法

4、以 test_ 开头的类里面的方法

5、所有的包 pakege 必须要有__init__.py 文件

2.pycharm执行用例配置

3.常用pytest执行用例命令

1.查看pytest命令行参数,可以用pytest -h 或pytest --help

2.执行当前文件夹下面的所有文件

python 复制代码
pytest 文件名/

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

python 复制代码
pytest 脚本名称.py

4.-k 匹配用例名称

执行测试用例名称包含qq的所有用例:

python 复制代码
pytest -k qq test_1.py

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

python 复制代码
pytest -k "not qq" test_1.py

同时匹配不同的用例名称

python 复制代码
pytest -k "wechat or webo" test_1.py

5.按节点运行

每个收集的测试都分配了一个唯一的nodeid,它由模块文件名和 :: 组成 来自参数化的类名,函数名和参数,由:: characters分隔

运行.py模块里面的某个函数:

python 复制代码
pytest test_mod.py::test_func

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

python 复制代码
pytest test_mod.py::TestClass::test_method

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

python 复制代码
pytest -x test_class.py

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

python 复制代码
pytest --maxfail=1

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

python 复制代码
pytest -q test_1.py

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

python 复制代码
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.跳过测试用例

7.1 @pytest.mark.skip

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

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

7.1 @pytest.mark.skipif(condition, reason="")

作用:希望有条件地跳过某些测试用例

注意:condition需要返回True才会跳过

python 复制代码
@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的长度需要与测试数据列表的长度一致
场景 :只有测试数据和期望结果不一样,但操作步骤是一样的测试用例可以用上参数化;

示例:

python 复制代码
#未参数化
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.[(),(),()...] 列表嵌套元组

python 复制代码
@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.[{},{},{}...] 列表嵌套字典

python 复制代码
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参数化之"笛卡尔积"

python 复制代码
# 笛卡尔积,组合数据
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个,所以最终的用例数有3 2=6条。当参数化装饰器有很多个的时候,用例数都等于nn nn...

8.4参数化之标记数据

python 复制代码
# 标记参数化
@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传递的数据:

python 复制代码
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定义

语法:

python 复制代码
@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清场功能。

相关推荐
缘友一世7 分钟前
Armbian 1panel面板工具箱中FTP服务无法正常启动的解决方法
linux·运维·后端·1panel
程序猿零零漆10 分钟前
【面向就业的Linux基础】从入门到熟练,探索Linux的秘密(十二)-管道、环境变量、常用命令
linux·运维·服务器
A-刘晨阳12 分钟前
ELFK 8.12.2 部署 -- docker部署方式⚽
linux·运维·elk·docker·容器
little redcap12 分钟前
下载linux的吐槽
linux·运维·服务器
j_linlian33 分钟前
Mac OS ssh 连接提示 Permission denied (publickey)
运维·ssh
大卫的纯爱战士35 分钟前
多线程网络实战之仿qq群聊的服务器和客户端
运维·服务器
网络研究院38 分钟前
Rejetto HFS 服务器存在严重漏洞受到攻击
运维·服务器·安全·黑客·漏洞·警告·hfs
jcLee951 小时前
运维系列.Nginx中使用HTTP压缩功能
运维·nginx·http
coisini.cn1 小时前
基于CentOS Stream 9平台搭建RabbitMQ3.13.4以及开机自启
linux·运维·服务器·rabbitmq·centos stream 9
林叔聊渠道分销1 小时前
从0到1构建渠道运营体系:实战案例与策略指南
大数据·运维·人工智能·产品运营·流量运营·渠道运营