fixture (使用pytest.fixture 替换使用setup, yield替换使用teardown)

Posted qika

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了fixture (使用pytest.fixture 替换使用setup, yield替换使用teardown)相关的知识,希望对你有一定的参考价值。


fixture   (是pytest特有的功能)           # fixture 官方文档::        https://docs.pytest.org/en/stable/fixture.html       

 

1、fixture特点:
必须用pytest.fixture装饰器装饰;fixture有明确的名字,在其他函数(function,默认),模块(module),类(class)或整个工程(session)调用它时会被激活;

可以调用其他的fixture;
可以和测试函数写在同一个文件里;
fixture也可作为是预置项,在测试用例执行之前需要去配置它,执行完后去释放它;
fixture还提供了参数化功能,根据配置和不同组件来选择不同的参数;


查看fixture帮助源码:

fixture(scope="function", params=None, autouse=False, ids=None, name=None):
"""使用装饰器标记fixture的功能 可以使用此装饰器(带或不带参数)来定义fixture功能。 fixture功能会在运行测试之前调用它:test模块或类可以使用pytest.mark.usefixtures(fixturename标记) 测试功能可以直接使用fixture名称作为输入参数,在这种情况下,夹具实例从fixture返回功能将被注入。 """ :scope: scope 有四个级别参数 "function" (默认), "class", "module" or "session". :params: 一个可选的参数列表,它将导致多个参数调用fixture功能和所有测试使用它 :autouse: 如果为True,则为所有测试激活fixture func 可以看到它。 如果为False(默认值)则显式需要参考来激活fixture :ids: 每个字符串id的列表,每个字符串对应于params 这样他们就是测试ID的一部分。 如果没有提供ID它们将从params自动生成 :name: fixture的名称。 这默认为装饰函数的名称。 如果fixture在定义它的同一模块中使用,夹具的功能名称将被请求夹具的功能arg遮蔽; 解决这个问题的一种方法是将装饰函数命名。“fixture_ <fixturename>”然后使用”@ pytest.fixture(name =‘<fixturename>‘)“”。

 

根据上述fixture介绍的总结:

fixture的参数scope可传递的4种类型:

function:每个test都运行,默认是function的scope
class:每个测试类之前执行一次
module:每个module的所有test只运行一次
session:每个session只运行一次(跨.py文件运行)

 

 

 

2、使用firture相对于setup和teardown的优缺点:

命名方式灵活,不局限于setup和teardown名称命名
conftest.py 配置里可以实现数据共享,不需要import就能自动找到一些配置
scope="module" 可以实现多个.py跨文件共享前置条件, 每一个.py文件调用一次
scope="session" 以实现多个.py跨文件使用一个session来完成多个用例(也就是当我们有多个.py文件的用例时候,
如果多个用例只需调用一次fixture,那就可以设置为scope="session",并且写到conftest.py文件里)

 

 

3、fixture在脚本用例当中的使用:

 一般用来装饰用例执行前的预置条件项,并且写进配置文件(conftest.py,一般配置文件的命名)

即:用于用例执行前的预置条件存放 (跟setup eardown相类似作用)。

(如在同一.py文件内,或不同.py文件内,一个用例要登录后才能操作其他的,而有些用例又不需要登录。那么此时setup就无法实现,而fixture可以)

 


4、实际应用:
1、@pytest.fixture()-----------------类似setup
2、@pytest.fixture(scope=‘module‘)---类似setup
3、yield ----------------------------类似teardown

 

4.1、当在相同一个.py文件内,调用相同方法时:

新建:test_demo.py
import pytest @pytest.fixture() #@pytest.fixture()里面没有参数,此时默认scope="function",此时针对函数有效 def login(): #fixture装饰的函数,是可以有return 返回值的,如果没有return默认是None。   print("输入账号,密码进行登录") def test_case1(login): #需要登录,传入login   print("用例1") def test_case2(): # 不传login   print("用例2") if __name__ == "__main__":    pytest.main(["-v", "test_demo.py"])

上述的例子:

假设用例要调用被fixture装饰过的函数的返回值,直接把被fixture装饰过的函数名称当成变量名称传入就行了
(例子中的:login是登录的函数,因为被fixture装饰后,可以把函数名当做参数传入会使用要先login的用例中)

 


4.2、当有多个.py文件都需要调用相同的功能时,那么就可以建一个配置文件,然后在pytest中会默认读取conftest.py里面的配置

新建配置文件: conftest.py:
import pytest
@pytest.fixture()      #不传参数时默认是@pytest.fixture(scope="function")
def login():
  print("这是登录功能")

  

新建test_demo1.py:
import pytest
def test_case1(login): #传入login
  print("用例1")

def test_case2(): # 不传login
  print("用例2")

if __name__ == "__main__":
  pytest.main(["-v", "test_demo1.py"])

 

新建test_demo2.py:
import pytest def test_case4(login): #传入login   print("用例4") def test_case5(): # 不传login   print("用例5") if __name__ == "__main__":   pytest.main(["-v", "test_demo2.py"])

结果可见:

将login函数写到了配置文件中,且使用@pytest.fixture装饰login函数;

然后单独去运行demo1.py或者demo2.py,都可以实现分别去调用登录方法,而不会受影响

 

 

同上面的 例4.1 是@pytest.fixture( ) 不传参数的操作,

如果传参数:

@pytest.fixture(scope=‘module‘)       module作用是整个.py文件都会生效,用例调用时,直接将函数名传入当做用例参数

例1:新建test_demo.py:(当都调用相同的操作方法时)
import pytest
@pytest.fixture(scope="module")
def open():
  print("打开浏览器访问至百度首页")

def test_case1(open):
  print("用例1")

def test_case2(open):
  print("用例2")

if __name__ == "__main__":
  pytest.main(["-s", "test_demo.py"])

运行结果会看见:2个用例都调用了open,open()方法会在执行用例前 运行一次

 

例2:新建test_demo.py:   (当一个用例调用,一个用例不调用时)
import pytest
@pytest.fixture(scope="module")
def open():
  print("打开浏览器访问至百度首页")

def test_case1():
  print("用例1")

def test_case2(open):   #case2引用open函数
  print("用例2")

if __name__ == "__main__":
  pytest.main(["-s", "test_demo.py"])

结果open只会在case2之前运行一次。(因为只case2 使用了open函数)

  

 

4.3、yield 实现结束操作(同teardown)

新建test_demo.py:

import pytest
@pytest.fixture(scope="module")
def open():
  print("打开浏览器,访问至百度首页")

  yield           #编写用例时,将yield写在结束操作之前就可,然后在所有用例执行完之后执行一次
  print("这是teardown操作")
  print("关闭浏览器")

def test_case1(open):
  print("用例1")

def test_case2(open):
  print("用例2")

if __name__ == "__main__":
  pytest.main(["-v", "test_demo.py"])


结果:上面的用例都调用了open()操作,在所有用例执行前执行一次open,然后运行用例,最后所有用例执行完之后执行一次yield后面的结束操作
注:yield在用例里面充当了teardown操作。就算用例执行报错,yield还是会正常执行不会被影响

  

以上是关于fixture (使用pytest.fixture 替换使用setup, yield替换使用teardown)的主要内容,如果未能解决你的问题,请参考以下文章

pytest文档23-使用多个fixture和fixture直接互相调用

pytest文档23-使用多个fixture和fixture直接互相调用

pytest-fixture

pytest-23-使用多个fixture和fixture直接互相调用

Pytest

pytest----fixture--使用fixture执行配置及销毁逻辑