pytest -html:测试报告生成插件
pytest与unittest的区别还有一点是,pytest自带的有测试报告生成的插件,下载pytest生成测试报告的插件,打开电脑终端cmd输入:pip install pytest-html
我们如何使用pytest生成测试报告:
import pytest
class Testmethod:
@pytest.mark.parametrize(('name','age'),[("小明",18),('李雷',20),('韩梅梅',25)])
def test_a(self,name,age):
print(name+'今年'+str(age))
对于以上代码我们可以在pycharm终端运行,进入当前路径输入以下命令:
pytest -s test_one.py --html=report.html
运行结果我们可以看到:
我们可以看到结果运行成功,当前路径生成测试报告report.html文件,复制路径浏览器打开报告:
我们可以看到测试报告记载了,测试用例个数,耗时,通过失败情况!我们不需要unittest在借助Htmltestrunnerl文件,我们只需下载pytest -html插件即可!
pytest-rerunfailures:重试机制
pytest框架还提供了一种错误重试机制,这是unittest所不具备的,当我们某个用例执行失败了,可能是由于环境问题或者网络问题导致,我们加上重试机制,那么它会在进行重试!
打开电脑终端cmd输入:pip install pytest-rerunfailures
插件安装完成之后,我们可以进行简单的demo!
import pytest
class Testmethod:
@pytest.mark.parametrize(('name','age'),[("小明",'18'),('李雷','20'),('韩梅梅',25)])
def test_a(self,name,age):
print(name+'今年'+age)
以上我们可以看到,最后一个参数age的值为int类型,我们下面打印的时候才用了字符串的拼接,这个时候应当会typeerror,类型错误。
在pycharm中打开终端运行以下命令:
pytest -s test_one.py --html=report.html --reruns 1 --reruns-delay 1
–reruns 1是指重试几次,后面跟的值是重试的次数,–reruns-delay 1是指重试的间隔时间,当失败后,需等待多久时间进行下一次的重试,后面跟的数据单位是秒,每隔一秒重试,我们可以看到运行结果:
我们可以看到控制台输出与测试报告的结果,存在了一次重试,还是失败了。
自定义pytest运行规则:pytest.ini
同学可以注意到,我们每次运行的时候都需要在控制台输出一长串命令,如果我们需要执行多个文件,每次都这样岂不是很麻烦吗?所以我们来讲解一下,如何自定义pytest的运行规则。
首先我们需要在当前存放测试文件的路径下新建一个.ini文件(配置文件),例如我们新建一个pytest.ini(可以是非当前路径,为了规范与管理,我们尽量放在一个路径下面)
然后我们可以在pytest.ini文件中进行以上编辑,首先[pytest]是声明,以pytest方式执行的文件,会自动读取到这个文件,addopts=后面是填写我们需要以什么样的方式执行,-s执行,并且生成测试报告,且带有重试机制,testpaths后面是我们执行的路径,执行的是哪一个文件夹下的文件,python_files=后面填写的是我们执行的文件是什么名称类型的文件,以test_开头的py文件,python_classes后面是文件里面以什么样名称格式的类,只执行Test开头的类,python_functions后面写的是以什么样的名称的方法,只执行以test开头的函数。
Fixture功能:
我们都知道pytest中也存在setup,teardown方法,前置与后置,fixture也具备这一功能。
import pytest
@pytest.fixture()
def data():
print('开始了')
return 2
def test_1(data):
print(2+data)
def test_2(data):
print(data)
if __name__ == '__main__':
pytest.main(['-s','test_one.py'])
可以运行以上代码,我们可以看到效果:
data函数被执行了两次,每个用例传在括号后面传入data,在执行用例前都回去执行一次data函数,类似于setup前置函数。
import pytest
@pytest.fixture()
def data():
print('开始了')
yield
print('结束了')
def test_1(data):
print('第一个用例')
def test_2(data):
print('第二个用例')
if __name__ == '__main__':
pytest.main(['-s','test_one.py'])
可以看到以上代码,我们在data函数后面加了一个yield关键字,运行以上代码:
会发现每个用例执行了一次yield前面的内容,然后结束后又执行了一次yield后面的内容,这个形式类似于teardown函数。可以存在多个fixture,在执行用例前,只要传入了fixture的函数,自然就会去执行。
fixture的作用域有四个session–>module–>class–>function,
session:同一个目录下,所有的文件都只执行一次
module:一个文件就会执行一次
class:一个类就会执行一次
function:一个函数就会执行一次(用的话直接把函数名做参数传到用例方法括号内),可省略不写
接下来我么看个示例:
import pytest
@pytest.fixture(scope='function')
def data():
print('开始了')
yield
print('结束了')
def test_3(data):
print('第三个用例')
class Testmethod():
def test_1(self,data):
print('第一个用例')
def test_2(self,data):
print('第二个用例')
if __name__ == '__main__':
pytest.main(['-s','test_one.py'])
我们可以看到这次fixture的作用域是function,意思是指,每个函数运行时,只要调用,都会先执行fixture的方法:
我们可以看到三个用例全部都调用了fixture的函数。
接下来我们看下fixture的作用域在class时的效果:
import pytest
@pytest.fixture(scope='class')
def data():
print('开始了')
yield
print('结束了')
class Testmethod():
def test_1(self,data):
print('第一个用例')
def test_2(self,data):
print('第二个用例')
if __name__ == '__main__':
pytest.main(['-s','test_one.py'])
运行以上代码:
我们可以看到每个用例都调用了fixture的函数,但是只执行了一次,这个时候fixture函数起到了setup_class与tesrdown_class的作用,类前置与类后置。
我们再来看一下fixture作用在module时的效果:
import pytest
@pytest.fixture(scope='module')
def data():
print('开始了')
yield
print('结束了')
class Testmethod():
def test_1(self,data):
print('第一个用例')
def test_2(self,data):
print('第二个用例')
class Testmethod1():
def test_1(self,data):
print('第一个用例')
def test_2(self,data):
print('第二个用例')
if __name__ == '__main__':
pytest.main(['-s','test_one.py'])
这个时候我们看到这个文件中存在两个类,运行以上代码:
结果显示我们只运行了一次,这个时候fixture的作用是在一个文件,一个文件执行只会执行一次!
至于当fixture作用于session时,意思就是多个文件执行,却只会执行一次,但是fixture的函数我们只在某一个文件中,这个时候我们应该怎么做?fixture装饰的函数,我们可以统一放在当前路径下的conftest文件中,当前文件执行时,会自动读取conftest文件中的fixture装饰的函数有没有被引用。
所以fixture的函数下次我们为了方便统一管理,可以尽量都放在conftest文件中,其他测试文件可直接进行调用。
Fixture的参数化:
import requests
import pytest
paramsdata = [{'data':{"accesstoken":"b0219c3d-b675-4749-82a5-bda469c8cf0e1","title":"你大爷的今天吃的啥","tab":"ask","content":"fhjdshjgrurehdjhjdfgdsg"},
'headers':{},
'status_code':200,
'payload':{}},
{'data':{"accesstoken": "b0219c3d-b675-4749-82a5-bda469c8cf0e1", "title": "你二大爷的今天吃的啥", "tab": "job", "content": "fhjdshjgrurehdjhjdfgdsg"},
'headers': {},
'status_code': 200,
'payload': {}},
{'data':{"accesstoken": "b0219c3d-b675-4749-82a5-bda469c8cf0e1", "title": "你大娘的今天吃的啥", "tab": "ask", "content": "fhjdshjgrurehdjhjdfgdsg"},
'headers': {},
'status_code': 200,
'payload': {}
}]
@pytest.fixture(params=paramsdata)
def class_scope(request):
return request.param
def test_001(class_scope):
url='http://39.107.96.138:3000/api/v1/topics'
respone=requests.post(url,data=class_scope['data'],headers=class_scope['headers'])
try:
assert respone.status_code==class_scope['status_code']
except Exception as e:
print(respone.text)
raise e
if __name__ == '__main__':
pytest.main(['-s','test_api.py'])
以上代码是fixture参数化的功能实现的,我们不需要依次对参数进行遍历循环读取,fixture就可实现这一功能,具体使用方法,同学们,可自行参考上述代码。