pytest本身属于UnitTest的升级版。在python环境中,pytest可以直接调用UnitTest的内容来进行实现。pytest是一个非常成熟的测试框架,最大的特点就是具备有各种第三方库的支持。对于使用方面会更加的自由。
pip install pytest/pip3 install pytest
可以在cmd之中输入pytest --version来校验环境部署是否成功
关于更多pytest的使用,可以百度搜索pytest官网,看到更加完整的信息和使用API
pytest与UnitTest有一个非常大的区别,就是pytest可以通过命令行指令进行用例的执行,从而实现到更加完整的指令配置。
Pytest在定义测试相关的内容时,所有的东西在默认配置情况下,需要遵循规则:
- 所有的测试文件都需要满足到test_*.py的格式,或者是*_test.py的格式
- 所有测试类,以及测试用例都需要以test开头,类就是Test*,用例就是test_。
- pytest有非常多的装饰器来实现对用例的功能增强。所以很多时候的逻辑处理,可以优先考虑装饰器的形态来实现。(装饰器也会具体讲解)
- 所有的运行指令以及文件和用例的获取,都可以在配置项中手动修改,通过pytest.ini文件实现。
所有的测试用例都是以test开头,其中在unitTest中用例会按照一定的顺序进行排序,在pytest中是按照书写的顺序运行。
测试用例的定义不会进行额外的排序操作,用例顺序如何写的就会如何执行。不是一定需要class类,也可以直接在py文件之中进行用例的编写。只是说通过class可以更好对用例来进行管理。
import pytest
#测试用例的定义
def test_function_03():
print('这是function_03')
def test_function_02():
print('这是function_02')
def test_function_01():
print('这是function_01')
class TestHcc1:
def test_01(self):
print('这是function011111')
if __name__ == '__main__':
pytest.main()
说明pytest既可以通过class管理测试用例,也可以直接使用方法来执行测试用例。
pytest和unitest另一个比较大的区别在于:pytest可以通过指令运行
pytest运行指令:在pytest指令参数中,有-和--的区别,单个字母则用-,词组则用--来进行指定。
1. pytest 表示运行从当前目录下开始,获取到的所有测试用例
2. pytest 文件路径及名称.后缀,来实现对指定的文件进行用例的执行,如果是指定文件运行,则可以不用以test做为文件名称的开头
3. -v 表示显示详细的信息。可以清晰了解到用例的具体执行情况,以及本次的pytest执行内容包括哪些。
4. -s 表示显示出print的内容
5. -q 表示静默执行测试内容。可用可不用
6. test_hcc.py::TestHcc1::test_01 指定测试用例来执行运行 文件及路径::class名称::测试用例名称 表示执行指定的文件下的class中的某一个测试用例
7. -x 出错之后就即刻停止,后续的剩余测试用例都将不再执行
8. --maxfail=num数值 num数值为int类型,表示定义到最大的报错用例数,当用例出错到最大数值时,用例运行全部终止,后续未执行用例,本次不再执行。
9. -k 类名 表示只执行指定的class类中的测试用例
10. -n 进程数量 进程数量为int类型,多进程运行大批量的测试用例。当测试用例数量过大的时候,可以通过此方法来提速。但是在用例设计上需要提前做好多进程的规划
调用多进程运行方式,需要提前进行pytest-xdist插件的安装,pip3 install pytest-xdist
import pytest
#测试用例的定义
def test_function_03():
print('这是function_03')
def test_function_02():
print('这是function_02')
def test_function_01():
print('这是function_01')
class TestHcc1:
def test_01(self):
print('这是function011111')
if __name__ == '__main__':
pytest.main()
打开终端-》进入要运行的文件夹-》输入pytest,就可以获取该目录下的所有测试用例
通过pytest指令可以获取到这三个文件夹中的测试用例,总共获取12个测试用例。
通过名称.后缀 (pytest ./test_hcc2.py),只能获取到这个文件test_hcc2中的测试用例,获取其中的4个测试用例。
没有-v是比较粗略的看到日志信息,是否通过测试用例,需要通过.F来告知
有-v的情况下,输出的内容是相对详细的。 具体看出有哪些函数并且成功还是失败。
import pytest
#测试用例的定义
def test_function_03():
print('这是function_03')
def test_function_02():
print('这是function_02')
def test_function_01():
print('这是function_01')
class TestHcc1:
def test_01(self):
print('这是function011111')
if __name__ == '__main__':
# main方法可以实现对指令的传入,但是传入很有限。
pytest.main()
通过-s,可以打印出具体的内容
import pytest
#测试用例的定义
def test_function_03():
assert 1==2
print('这是function_03')
def test_function_02():
print('这是function_02')
def test_function_01():
print('这是function_01')
比如断言失败了之后,就会直接停止下面的用例不再进行,报错stopping after 1 failures 。
- --maxfail=num数值 num数值为int类型,表示定义到最大的报错用例数,当用例出错到最大数值时,用例运行全部终止,后续未执行用例,本次不再执行。
可以看到运行结果, 不同的进程,管理不同的测试用例。
对于异常的测试用例,可以实现非常多的管理手段,包括用例执行管理、缺陷管理、问题排查管理等非常多的内容,结合业务实际需要,我们在实际测试中通过xfail装饰器可以更好地管理异常用例相关内容。
@pytest.mark.xfail() # 表示当前标记的该用例,在执行之前已经预期会失败了。
def test_function03():
print('这是function03')
assert 1 == 2
表示当前标记的该用例,在执行之前已经预期会失败了。XFAIL表示符合预期。
实际应用:
@pytest.mark.xfail()装饰器,与UnitTest下的expectedFailed类似,都是预期会失败的测试用例。
有些用例的实际对应内容,或者因为特定的bug,导致用例本身一定会失败的情况,可以进行xfail标记。
运行时,报错了,表示符合预期,XFAIL
运行时,成功了,表示不符合预期,XPASS
xfail不仅可以用于装饰器,也可以进行xfail方法的调用。
# xfail装饰器的调用
@pytest.mark.xfail(True, reason="这是reason", run=False)
def test_function():
li = [1, 2, 3]
# print(li[10])
# xfail的方法调用
def test_function1():
for i in range(0, 10):
if i == 5:
pytest.xfail('该条用例执行失败,标记为XFAIL') # 调用xfail方法
else:
print(i)
if __name__ == '__main__':
pytest.main()
观察运行结果,当进行xfail的调用时,运行到xfail处之后,就会提前结束运行。
xfail装饰器提供有默认的参数: 1. condition参数,当condition为true的时候,xfail会生效,为False则不会生效。 2. reason参数,当condition为True的时候,会显示reason相关内容。 3. strict参数,默认为False,当设置为True时,用例正常运行成功,则显示为Failed 4. raises参数,抛出指定的异常。用例运行时,失败的时候会生成有异常信息,该参数设置就是指定我们期望会抛出的异常 5. run参数,默认为True,表示是否要运行被xfail标记的用例,为False时,则直接返回xfail,不执行该条测试用例
Pytest下测试用例的应用: 常规的测试用例执行与调用相关的内容与UnitTest基本没有区别。 skip管理测试用例:标记测试用例,用于在当前进行跳过的处理 定义统一的跳过条件设定,然后通过装饰器来对需要调用的用例进行使用。可以更好地管理测试用例。
- 无条件跳过
- 有条件跳过
- 自定义条件跳过
无条件跳过:
import pytest
#对测试用例执行无条件跳过
@pytest.mark.skip('这是无条件跳过的skip')
def test_function():
print('这是一个基本的测试用例')
查看结果:
有条件跳过:符合条件跳过,不符合条件,不跳过
# 有条件跳过
@pytest.mark.skipif(1 == 1, reason='这是有条件跳过')
def test_function02(self):
print('这是一个基本的测试用例02')
可以自定义一个skip装饰器
import pytest
#定义统一的跳过条件设置
hccskip = pytest.mark.skipif(1==1,reason='这是hccskip')
#对测试用例执行无条件跳过
@pytest.mark.skip('这是无条件跳过的skip')
def test_function():
print('这是一个基本的测试用例')
# 有条件跳过
@pytest.mark.skipif(1 == 1, reason='这是有条件跳过')
def test_function02(self):
print('这是一个基本的测试用例02')
@hccskip
def test_function03():
print('这是一个基本的测试用例03')
然后在第三个测试用例中引入这个自定义的装饰器,查看结果,这几个用例都被成功跳过。
如果所有的测试用例,我们都不想让他执行,就设置类级别的测试用例。可以跳过所有的测试用例。pytestmark名称是固定的。
pytestmark = pytest.mark.skip('这是类级别的skip')
@pytest.mark:在pytest中,不同的测试我们可以对其进行分类。对测试用例进行更精细化的管理。区分不同用例之间的功能。在unitTest中,为了区分不同的业务代码,我们会将所有的业务代码加入不同的测试套件。
标签定义名称的时候,不建议太复杂,标签本身根据实际需要进行定义即可。
pytest -m "hcc"表示将所有mark.hcc的测试用例进行获取并执行。
pytest -m "not hcc" 表示获取所有非hcc的测试用例进行执行。
pytest -m "hcc or xzl" 表示获取所有hcc或者xzl的测试用例进行执行。
pytest -m "hcc and xzl" 表示获取所有hcc和xzl同时标记的测试用例进行执行。
mark可以根据不同的用途对测试用例进行标记。
import pytest
@pytest.mark.aa
def test_function01():
print('这是aa的测试用例')
@pytest.mark.bb
def test_function02():
print('这是bb的测试用例')
@pytest.mark.aa
@pytest.mark.bb
def test_function03():
print('这是aa和bb的测试用例')
@pytest.mark.parametrize是pytest中的参数化形态。用于处理整个pytest中的数据驱动的一个装饰器。
UnitTest下的ddt模块,在pytest中不推荐使用。
@pytest.mark.parametrize(argnames,argvalues)
argnames表示参数的名称,要与用例的形参名称保持一致。
argvalues表示参数的值,如果有多个,则通过list进行传递。不同参数用元组包含 。
import pytest
#简单的参数化
@pytest.mark.parametrize("a,b",[(1,2)])
def test_function_01(a,b):
print(a+b)
按照上面的逻辑,应打印出3。查看运行结果
如果把a,b分开打印,也会根据传入的顺序,打印出来
import pytest
#简单的参数化
@pytest.mark.parametrize("a,b",[(1,2)])
def test_function_01(a,b):
print(a)
print(b)
查看结果:
如果想要传多个参数,就直接在参数值处加上就行。如果有多组测试数据需要传递的话,则用例也会基于拆解的数据组数进行对应数量重复的用例执行 如果要传入固定的数据内容,一定记得在外面用[]把数据括起来
import pytest
#简单的参数化
@pytest.mark.parametrize("a,b",[(1,2),(22,22)])
def test_function_01(a,b):
print(a)
print(b)
查看结果:
在unittest中对于yaml文件,是通过@filedata装饰器进行的。
在pytest中是通过parametrize实现yaml文件的内容读取
提前准备的yaml文件:
在pytest中通过parametrize实现yaml文件的内容读取
@pytest.mark.parametrize("data", yaml.load(stream=open('./login.yaml', 'r', encoding='utf-8'), Loader=yaml.FullLoader))
def test_function_03(data):
print(data)
查看结果:
多个参数分别管理,可以执行实现用例中的数据循环嵌套,实现所有的数据搭配组合
@pytest.mark.parametrize('a',[1,33,1111])
@pytest.mark.parametrize('b',[2,3,1])
def test_function_04(a,b):
print('这是完整的参数内容:{}和{}'.format(a,b))
Pytest下,通过assert进行断言。
对于失败的用例,pytest提供有失败重跑机制。可以通过指令--lf来实现,指令全称就是last failed
1. 将上一次运行的用例中,所有失败的测试用例重新执行一次。
2. 如果上一次运行的用例全部都成功了,则会将上一次的所有用例都执行一次 重新运行所有用例,但失败的用例优先运行,可以通过指令--ff来实现。指令全称就是failed first 用例执行次数,在执行用例的时候,可以手动设置本次用例的执行总次数。 通过--count=次数 来定义,次数为int值。 要调用这个指令需要pip install pytest-repeat之后才可以生效
Pytest下,通过assert进行断言。
def test_function1():
assert 1==2
def test_function2():
assert 1==1
def test_function3():
assert 1==3
查看结果:可以看到一个成功的,两个失败的
对于失败的用例,pytest提供有失败重跑机制。可以通过指令--lf来实现,指令全称就是last failed将上一次运行的用例中,所有失败的测试用例重新执行一次。
可以看到两条失败的,一条成功的被忽略了。
失败的用例优先运行,可以通过指令--ff来实现,可以看到两条失败的用例被优先重跑了。