一、Pytest环境部署

 pytest本身属于UnitTest的升级版。在python环境中,pytest可以直接调用UnitTest的内容来进行实现。pytest是一个非常成熟的测试框架,最大的特点就是具备有各种第三方库的支持。对于使用方面会更加的自由。

安装

pip install pytest/pip3 install pytest 

可以在cmd之中输入pytest --version来校验环境部署是否成功

关于更多pytest的使用,可以百度搜索pytest官网,看到更加完整的信息和使用API

pytest与UnitTest有一个非常大的区别,就是pytest可以通过命令行指令进行用例的执行,从而实现到更加完整的指令配置。

二、 Pytest基本应用

Pytest在定义测试相关的内容时,所有的东西在默认配置情况下,需要遵循规则:

所有的测试文件都需要满足到test_*.py的格式,或者是*_test.py的格式所有测试类,以及测试用例都需要以test开头,类就是Test*,用例就是test_。pytest有非常多的装饰器来实现对用例的功能增强。所以很多时候的逻辑处理,可以优先考虑装饰器的形态来实现。(装饰器也会具体讲解)所有的运行指令以及文件和用例的获取,都可以在配置项中手动修改,通过pytest.ini文件实现。

2.1测试用例管理

 所有的测试用例都是以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管理测试用例,也可以直接使用方法来执行测试用例。

  2.2Pytest基本指令讲解

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

pytest指令:表示运行从当前目录下开始,获取到的所有测试用例

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 文件路径及名称.后缀:来实现对指定的文件进行用例的执行

通过pytest指令可以获取到这三个文件夹中的测试用例,总共获取12个测试用例。

 通过名称.后缀  (pytest ./test_hcc2.py),只能获取到这个文件test_hcc2中的测试用例,获取其中的4个测试用例。

  -v 表示显示详细的信息。可以清晰了解到用例的具体执行情况,以及本次的pytest执行内容包括哪些。

没有-v是比较粗略的看到日志信息,是否通过测试用例,需要通过.F来告知 

有-v的情况下,输出的内容是相对详细的。 具体看出有哪些函数并且成功还是失败。

 

 -s 表示显示出print的内容

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,可以打印出具体的内容

 

-q  :表示静默执行测试内容。可用可不用。显示的内容非常精简

 

  test_hcc.py::TestHcc1::test_01指定测试用例来执行运行 文件及路径::class名称::测试用例名称 表示执行指定的文件下的class中的某一个测试用例。就只运行了test_hcc下面的TestHcc1下面的test_01一个内容。

 

 -x :出错之后就即刻停止,后续的剩余测试用例都将不再执行。

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类型,表示定义到最大的报错用例数,当用例出错到最大数值时,用例运行全部终止,后续未执行用例,本次不再执行。  

-n 进程数量  进程数量为int类型,多进程运行大批量的测试用例。当测试用例数量过大的时候,可以通过此方法来提速。提前进行pytest-xdist插件的安装,pip3 install pytest-xdist

可以看到运行结果, 不同的进程,管理不同的测试用例。

 

2.3Xfail装饰器

对于异常的测试用例,可以实现非常多的管理手段,包括用例执行管理、缺陷管理、问题排查管理等非常多的内容,结合业务实际需要,我们在实际测试中通过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装饰器相关参数 

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,不执行该条测试用例

 2.4skip装饰器

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')

2.5mark装饰器

@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的测试用例')

2.5.1 mark.parametrize

@pytest.mark.parametrize是pytest中的参数化形态。用于处理整个pytest中的数据驱动的一个装饰器。

UnitTest下的ddt模块,在pytest中不推荐使用。

@pytest.mark.parametrize(argnames,argvalues)

argnames表示参数的名称,要与用例的形参名称保持一致。

argvalues表示参数的值,如果有多个,则通过list进行传递。不同参数用元组包含 。

 2.5.1.1单个参数管理 

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)

查看结果:

  2.5.1.2多个参数管理 

如果想要传多个参数,就直接在参数值处加上就行。如果有多组测试数据需要传递的话,则用例也会基于拆解的数据组数进行对应数量重复的用例执行 如果要传入固定的数据内容,一定记得在外面用[]把数据括起来

import pytest

#简单的参数化

@pytest.mark.parametrize("a,b",[(1,2),(22,22)])

def test_function_01(a,b):

print(a)

print(b)

查看结果:

 

2.5.1.3yaml文件传入  

在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)

 查看结果:

2.5.1.4多个参数分别管理

多个参数分别管理,可以执行实现用例中的数据循环嵌套,实现所有的数据搭配组合

@pytest.mark.parametrize('a',[1,33,1111])

@pytest.mark.parametrize('b',[2,3,1])

def test_function_04(a,b):

print('这是完整的参数内容:{}和{}'.format(a,b))

 

2.6断言 

 Pytest下,通过assert进行断言。

对于失败的用例,pytest提供有失败重跑机制。可以通过指令--lf来实现,指令全称就是last failed

1. 将上一次运行的用例中,所有失败的测试用例重新执行一次。

2. 如果上一次运行的用例全部都成功了,则会将上一次的所有用例都执行一次 重新运行所有用例,但失败的用例优先运行,可以通过指令--ff来实现。指令全称就是failed first 用例执行次数,在执行用例的时候,可以手动设置本次用例的执行总次数。 通过--count=次数 来定义,次数为int值。 要调用这个指令需要pip install pytest-repeat之后才可以生效

 2.6.1基本断言

Pytest下,通过assert进行断言。

def test_function1():

assert 1==2

def test_function2():

assert 1==1

def test_function3():

assert 1==3

 查看结果:可以看到一个成功的,两个失败的

        2.6.2 断言失败重跑机制

 对于失败的用例,pytest提供有失败重跑机制。可以通过指令--lf来实现,指令全称就是last failed将上一次运行的用例中,所有失败的测试用例重新执行一次。

可以看到两条失败的,一条成功的被忽略了。

 

2.6.3失败用例优先重跑 

 失败的用例优先运行,可以通过指令--ff来实现,可以看到两条失败的用例被优先重跑了。

 

好文推荐

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: