这篇文章上次修改于 588 天前,可能其部分内容已经发生变化,如有疑问可询问作者。
安装
- pip install pytest
规范
- 测试用例 test__ 或者 _test 开头
- 测试类 使用 Test 开头
- 文件使用 test 开头
pytest用例执行机制,测试用例执行场景,批量执行,指定特定的测试用例执行
标记测试用例 mark
@pytest.mark.testcase def test_make(): assert 2 == 2
查看测试用例名称
关键字:--collect-only 语法:pytest -q -s --collect-only 用例目录/用例
执行指定测试用例
1. pytest test_mod.py 执行指定测试用例 2. pytest testing_dir/ 执行指定测试目录下的测试用例
测试用例错误达到number个数停止执行用例 –maxfail=number
1. pytest -x pytest_base/base_debug.py 遇见第一个报错停止执行测试用例 2. pytest --maxfail=2 pytest_base/base_debug.py 遇见第2个报错停止执行测试用例
测试用例关键字执行
pyest -k 关键字 注意事项:python关键字不可以出现在 pytest -k 中
测试执行报告
1. -r: 可以在执行结束后,打印出简短的测试结果结果报告,在执行很多测试用例时,可以清晰的了解结果 2. -r后面紧跟一个参数,时过滤 3. 参数:f(失败) E(错误) p(通过) A(所有) s(跳过) 4. 参数:x(跳过执行,标记为xfailed的) X(跳过执行,标记为Xpassed的) 5. 参数:a(除了测试通过的,其他所有的) P(测试通过,并且有输出信息) pytest -q -s -r 测试用例 其他参数动手自行练习一下
用例错误信息诊断
pytest -pdb 如果测试用例执行fail, 那么将会打印出python诊断器详细的信息 在执行测试用例时启动pdb诊断器 pytest --trace -q -r 用例路径
分析测试用例的时间
pytest --durations=n 查看执行最慢的n个测试用例
fixture
定义
公共方法参数化fixture 在测试用例中,比如查询订单,需要用户token, 可以将生成的token参数化,代码复用,减少冗余代码, 可以理解成公共方法的封装
fixture参数 fixture(scope=“function”, params=None, autouse=False, ids=None, name=None)
scope参数:scope = “function”, scope = “module”, scope=“class”, scope=“package”
fixture: 作为形参使用,对应的fixture就是函数的返回值
@pytest.fixture def func(): sum = 3 + 2 return sum def test_one(func): assert func == 5 def test_two(func): assert func == 6 当test_one和test_two测试用例接收 func 函数时, fixture的作用是实例化函数, 然后返回 func 的值
fixture 使用参数介绍
1. fixture为session级别是可以跨.py模块调用的,也就是当我们有多个.py文件的用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope="session",并且写到conftest.py文件里。 2. module 在当前模块.py脚本里面所有用例开始前只执行一次 3. package 会作用于包内的每一个测试用例, 且只被调用一次 4. function 每个测试用例都会调用一次 5. class 如果一个class 中有多个测试用例, 在类中只调用一次 举个例子:在不同的测试用例目录下,有活动查询,活动下单,订单查询用例,都需要带token参数, 那么我们在conftest里封装获取token的方法,定义成:scope="session", 那么所有测试用例执行时的token值是相同的,这就是只执行一次。 如果定义成scope=class, 那么每个测试类都会执行一次,什么意思呢,比如我有3个测试用例类,那么token封装的方法就会执行3次,生成3个不同的token值。
fixture 使用规则
1. 如果想在多个测试模块中共用一个fixture, 可以把 fixture 移动到conftest.py中,测试模块不需要手动导入,pytest会自动导入。 2. fixture 自动导入的顺序: 测试类 > 测试模块 > conftest.py > 第三方插件
fixture 参数化
1. params是列表形式,参数列表用 request.param 遍历参数 @pytest.fixture(params=[(username, passwd)], ids=["A", "B", "C用户登录", "D", "E"]) def func1(request): x = request.param sum = x + x return sum 2. params是列表形式, 当参数是字典,request.param遍历参数 order = [ { "addr": "黄金书", "city": "shenzhen" }, { "addr": "福田", "city": "深圳" } ] @pytest.fixture(params=order) def func4(request): infor = request.param addr = infor["addr"] city = infor yiled addr 3. 同理,当参数是元组,或是其他数据类型,记住,首先params接收的是列表,然后处理列表里面的数据类型
fixture 的清理操作
比如在连接数据库时,操作完数据库之后,需要关闭数据库 将fixture函数中的 return 换成 yield, 则yield后面的代码就是我们需要清理的操作, 也可以用with
fixture 和 usefixtures的区别
1. 如果fixture有返回值,那么usefixture就无法获取到返回值,这个是装饰器usefixture与用例直接传fixture参数的区别。 例子: 创建conftest.py 文件 import pytest from pathlib import Path import os # 区分 userfixture 和 fixture #无返回值 @pytest.fixture(scope="session") def create_userfixture_dir(): path = "userfixture" os.mkdir(path, 770) #无返回值 @pytest.fixture(scope="session") def create_fixture_dir(): path = "fixture" os.mkdir(path, 770) #无返回值 @pytest.fixture(scope="function") def add_sum_one(): sum = 5 + 5 #有返回值 @pytest.fixture(scope="function") def add_sum_two(): sum = 5 + 5 return sum usefixtures_fixture_diff.py 文件 import pytest #调用时,生成userfixture目录 @pytest.mark.usefixtures('create_userfixture_dir') def test_usefixture(): pass #调用时,生成fixture目录 def test_fixture(create_fixture_dir): pass # 说明userfixture 和 fixture都可以调用无返回值的函数 # 这是个错误的测试用例,因为 usefixtures 不能接受返回值 @pytest.mark.usefixtures("add_sum_two") def test_add_sum_tow(): assert add_sum_two == 10 # fixture能接受函数返回值,所以断言成功 def test_add_sum_two_fixture(add_sum_two): assert add_sum_two == 10 userfixture使用场景:如活动在购物车结算失败,清空购物车信息,创建目录等。 fixture使用场景:如活动下单需要token, 定义生成token的方法,将值返回给方法函数,用于下单。
@pytest.mark.parametrize 测试用例参数化
parametrize(self,argnames, argvalues, indirect=False, ids=None, scope=None):
argvalues 有n个参数,pytest.mark.parametrize会依次取参进行测试
例子: @pytest.mark.parametrize('test_input, expected', [('3 + 5', 8)]) def test_data2(test_input, expected): print(test_input, expected) assert eval(test_input) == expected
测试用例标记
@pytest.mark.skip(reason=None) 无条件跳过测试用例
skip 源码 def skip(self,reason=None) 例子: @pytest.mark.skip(reason="无条件跳过") def test_one(): assert 3 == 4
pytest.mark.skipif(condition, reason=None) 有条件跳过测试用例
skipif 源码 def skipif(self,condition, reason=None): 当条件成立,才不执行测试用例,条件不成立,则执行测试用例 例子: num = 4 @pytest.mark.skipif(num == 4, reason="有条件跳过") def test_two(): assert 4 == 4
@pytest.mark.xfail(condition=None, reason=None, raises=None, run=True, strict=False)
xfail 源码 def xfail(self,condition=None, reason=None, raises=None, run=True, strict=False): 例子1: @pytest.mark.xfail(reason="期待为xfail") def test_xfail(): assert 8 == 9 期待测试用例为xfail, 当断言失败,用例标记为xfail,满足期待,当断言成功,测试用例标记为xpassed, 与预期相反 例子2: @pytest.mark.xfail(reason="期待为xfail", strict=True) def test_xfail_strict(): assert 8 == 9 当strcit参数为true时,测试用例不符合预期结果,将用例标记为fail
pytest第三方插件
pytest-rerunfailures
安装: pip install pytest-rerunfailures
功能介绍:当测试用例执行失败时,我们可以指定该测试用例的最大执行次数,如果在最大执行次数内执行通过,用例将不再执行
1. 命令:pytes --return 5 测试用例 2. 可以用 flaky 来进行标记 - @pytest.mark.flaky(reruns= ,reruns_de1lay=None) 例子: return_fail.py import pytest @pytest.mark.flaky(reruns=10,reruns_delay=1) def test_example(): import random num = random.randint(1, 10) assert num == 5
pytest 有许多有用的插件,不再举例说明,根据自己需求,用到时查询相关资料