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直接互相调用