Bootstrap

Pytest和Allure测试框架-超详细版+实战_pytest allure


也可以同时选择匹配 “http” 和“quick”



pytest -k “http or quick” -v


## 三, Pytest -fixture


下面都有实战很详细-fixture确实牛逼  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923150542126.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923151931931.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923152306626.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923152023292.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![](https://img-blog.csdnimg.cn/20190923152204432.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923151858213.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 pytest 相较于 unittest 最为跳跃的一点应该就是 fixture 机制


对于unittest来说,每个用例的类中都需要去写入setUp和tearDown。也就是我们所说的前置和后置,


而不可避免的,很多用例的前置和后置都是一样(例如很多用例都需要前置登录,后置退出),于是我们需要重复的复制粘贴,这样导致工作量增加,代码量也增加,界面也显得冗杂。


所以此时**pytest中fixture机制便要闪亮登场了**。


通俗的讲: fixture = 前置+后置


而方便的是:如果很多用例都有同样的前置和后置,那么我就只实现一个,然后需要的用例就去调用就好了。


**1.机制:与测试用例同级,或者是测试用例的父级,创建一个conftest.py文件。  
 2.conftest.py文件里:放所有的前置和后置。 不需要用例.py文件主动引入conftest文件。  
 3.定义一个函数:包含前置操作+后置操作。  
 4.把函数声明为fixture :在函数前面加上 @pytest.fixture(作用级别=默认为function)  
 5.fixture的定义。  
   如果有返回值,那么写在yield后面。(yield的作用就相当于return)  
   在测试用例当中,调用有返回值的fixture函数时,函数名称就是代表返回值。  
   在测试用例当中,函数名称作为用例的参数即可。**


### 1. 如下: 定义一个函数名叫open\_url的fixture前后置,前置为打开链接,后置为退出浏览器


@pytest.fixture(scope=“class”) #定义scope的范围



def open_url():
# 前置
driver = webdriver.Chrome()
driver.get(url) #url为链接地址
yield driver #yield之前代码是前置,之后的代码就是后置。
# 后置
driver.quit()


这样我们就定义了一个叫做 open\_url 的 fixture


### 2.在我们要用这个前后置的类前面 我们用@pytest.mark.usefixtures(fixture函数名)


就可以直接调用上面定义好的这个前后置  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923152610474.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 可以看到 在TestLogin 这个类中 我们不再去编写setup 和 teardown. 直接写我们的中间过程就可以了。是不是很方便了?


### 3.进阶方法:conftest中定义多个fixture,一个fixture可以是另一个fixture的前后置,期间还是用field隔开前后置


如上图中可以看到我class中另外还引用了一个名为refresh\_page的fixture,直接上代码:



刷新页面 - 定义的第二个fixture

@pytest.fixture
def refresh_page(open_url):
yield
open_url.refresh()


直接将open\_url作为了另一个fixture的前置引用进来,用yield隔开,当用例中执行完open\_url前后置后,再执行了一次refresh的后置。  
 执行顺序: open\_url yield 之前代码 – 用例代码 – open\_url yield 之后代码 --》 refresh\_page yield 之后代码  
 是不是很妙,可以解决许多用例流程环环相扣时的麻烦。


### 4.说到上面的多个fixture调用,很多人就会疑惑,会不会fixture之间相互冲突。


当然是不会了,fixture在conftest.py当中就已经决定了他的用例域,他会主动去区分你这个fixture是作用在哪个用例域。  
 首先我们看一下框架中对于fixture函数的定义: ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923152631516.png)


scope便是定义用例域的范围:  
 function:默认范围,每一个函数或方法都会调用,不填写时便是它  
 class:每一个类调用一次  
 module: 每一个.py文件调用一次,文件中可以有多个function和class  
 session:多个文件调用一次,可以跨文件,如在.py文件中,每一个.py文件就是module  
 范围:  
 session > module > class > function


所以在调用时各个fixture之间并不会相互冲突。


### 5,fixture的自动应用autouse


autouse调用例子:\*\*  
 当管理用例比较多的时候,这种方法比较方便高效,但是用该功能时也要小心,一定要注意fixture的作用范围。需要注意的是,当使用这种方式时,就不能使用返回值的功了。autouse默认设置为False。当默认为False,就可以选择用上面两种方式来试用fixture。当设置为True时,所有的test都会自动调用这个fixture。autouse遵循scope="关键字参数"规则:当scope="session"时,无论怎样定义只运行一次;当scope="module"时,每个py文件只运行一次;当scope="class"时,每个class只运行一次(但是一个文件中包括function和class时,会在每个function(不在class中)运行一次);当scope="function"时,每个function运行一次;  
 ‘’’  
 **平常写自动化用例会写一些前置的fixture操作,用例需要用到就直接传该函数的参数名称就行了。当用例很多的时候,每次都传这个参数,会比较麻烦。  
 fixture里面有个参数autouse,默认是Fasle没开启的,可以设置为True开启自动使用fixture功能,这样用例就不用每次都去传参了**


设置autouse=True  
 autouse设置为True,自动调用fixture功能  
 start设置scope为module级别,在当前.py用例模块只执行一次,autouse=True自动使用[图片]open\_home设置scope为function级别,  
 每个用例前都调用一次,自动使用



import pytest

@pytest.fixture(scope=“module”,autouse=True)
def start(request):
print(“\n----开始执行module------”)
print(‘module : %s’% request.module.name)
print(‘------启动浏览器-------’)
yield
print(“------结束测试 end!----------”)

@pytest.fixture(scope=“function”,autouse=True)
def open_home(request):
print(“function:%s \n–回到首页–”% request.function.name)

def test_01():
print(‘----用例01-----’)

def test_02():
print(‘----用例02-----’)

if name == ‘__main__’:
pytest.main([“-s”,“autouse.py”])


执行结果



----开始执行module------
module : autouse
------启动浏览器-------
function:test_01
–回到首页–
.----用例01-----
function:test_02
–回到首页–
.----用例02-----
------结束测试 end!----------


## 四,参数化与数据驱动框架实现


### 参数化1


![在这里插入图片描述](https://img-blog.csdnimg.cn/2019092315583535.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/2019092315584650.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923155857380.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)  
 ![在这里插入图片描述](https://img-blog.csdnimg.cn/20190923155909987.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQyNjEwMTY3,size_16,color_FFFFFF,t_70)



import pytest

@pytest.mark.parametrize(‘test_input,expected’,[(‘3+5’,8),
(‘2-1’,1),(‘7*5’,30)])
def test_eval(test_input,expected):
assert eval(test_input)==expected    ----eval把字符串转换成表达式

est_param.py::test_eval[2-1-1]
test_param.py::test_eval[7*5-30] PASSED [ 33%]PASSED [ 66%]FAILED [100%]
test_param.py:3 (test_eval[7*5-30])
35 != 30

Expected :30
Actual :35

test_input = ‘7*5’, expected = 30

@pytest.mark.parametrize(‘test_input,expected’,[(‘3+5’,8),
(‘2-1’,1),(‘7*5’,30)])
def test_eval(test_input,expected):

assert eval(test_input)==expected
E assert 35 == 30          ----提示把30改成35

test_param.py:7: AssertionError

Assertion failed


### 参数化2



import pytest
test_user_data=[‘linda’,‘sai’,‘tom’]
@pytest.fixture(scope=‘module’)
def login(request):
user=request.param
print(‘打开首页登陆%s’%user)
return user

#indirect=True是把login当作函数去执行
@pytest.mark.parametrize(‘login’,test_user_data,indirect=True)
def test_cart(login):
usera=login
print(‘不同用户添加购物车%s’%usera)
assert usera!=‘’

Process finished with exit code 0
打开首页登陆linda
PASSED [ 33%]不同用户添加购物车linda
打开首页登陆sai
PASSED [ 66%]不同用户添加购物车sai
打开首页登陆tom
PASSED [100%]不同用户添加购物车tom


### 参数化3



import pytest
test_user_data=[
{‘user’:‘linda’,‘password’:‘8888’},
{‘user’:‘servenruby’,‘password’:‘123456’},
{‘user’:‘test01’,‘password’:‘’}
]

@pytest.fixture(scope=‘module’)
def login_r(request):
#可以通过dict形式,虽然传递一个参数,但通过key的方式可以达到累死传入多个参数的效果
user=request.param[‘user’]
pwd=request.param[‘password’]
print(‘\n打开首页准备登陆,登陆用户%s,密码%s’%(user,pwd))
if pwd:
return True
else:
return False

#这是pytest参数化驱动,indeirect=True是把login_r当作函数去执行
@pytest.mark.parametrize(‘login_r’,test_user_data,indirect=True)
def test_cart(login_r):
#登陆用例
a=login_r
print(‘测试用例中login_r的返回值%s’%a)
assert a,‘失败原因,密码为空’

开首页准备登陆,登陆用户linda,密码8888
PASSED [ 33%]测试用例中login_r的返回值True

打开首页准备登陆,登陆用户servenruby,密码123456
PASSED [ 66%]测试用例中login_r的返回值True

打开首页准备登陆,登陆用户test01,密码
FAILED [100%]测试用例中login_r的返回值False

打开首页准备登陆,登陆用户linda,密码8888
PASSED [ 33%]测试用例中login_r的返回值True

打开首页准备登陆,登陆用户servenruby,密码123456
PASSED [ 66%]测试用例中login_r的返回值True

打开首页准备登陆,登陆用户test01,密码
FAILED [100%]测试用例中login_r的返回值False

test_mark_param_request2.py:19 (test_cart[login_r2])
login_r = False

@pytest.mark.parametrize(‘login_r’,test_user_data,indirect=True)
def test_cart(login_r):
#登陆用例
a=login_r
print(‘测试用例中login_r的返回值%s’%a)

assert a,‘失败原因,密码为空’
E AssertionError: 失败原因,密码为空
E assert False


### 参数化3\*3



import pytest
test_user_data1=[{‘user’:‘linda’,‘password’:‘888888’},
{‘user’:‘servenruby’,‘password’:‘123456’},
{‘user’:‘test01’,‘password’:‘’}]
test_user_data2=[{‘q’:‘中国平安’,‘count’:3,‘page’:1},
{‘q’:‘阿里巴巴’,‘count’:2,‘page’:2},
{‘q’:‘pdd’,‘count’:3,‘page’:1}]
@pytest.fixture(scope=‘module’)
def login_r(request):
#这是接受不了输入的参数,接收一个参数
user=request.param[‘user’]
pwd=request.param[‘password’]
print(‘\n用户名:%s,密码:%s’%(user,pwd))

@pytest.fixture(scope=‘module’)
def query_param(request):
q=request.param[‘q’]
count=request.param[‘count’]
page=request.param[‘page’]
print(‘查询的搜索词%s’%q)
return request.param

#这是pytest的数据驱动,indeirect=True是把login_r当作函数去执行
#从下往上执行

;