1、前言
- setup和teardown可以实现用例执行前和执行后加入一些操作,但是这种操作是全局的生效的
- 有一些操作,我们只想要做用在部分用例上,这时可以使用
fixture
来自定义前置操作
2、fixture参数列表
@pytest.fixture(scope="function", params=None, autouse=False, ids=None, name=None)
def login():
print("this is login")
参数列表:
scope
: 默认function
。可以理解为fixture的作用域,一般还有4种:class
module
package
session
(整个测试会话,即开始执行pytest到结束测试)autouse
:默认False,表示需要手动调用该fixture。如果是True,scope表示的作用域内的测试用例都会自动调用该fixturename
:默认:函数名称。如果配置了,调用fixture时使用该配置的名称,否则使用函数名即可调用
3、测试用例如何调用fixture
一般有三种方式:
- 将fixture名称作为测试用例函数的输入参数
- 测试用例使用装饰器:
@pytest.mark.usefixtures(fixture_name)
- fixture设置
autouse=True
说明:
- 如果在类声明上加
@pytest.mark.usefixures()
,代表这个类里面所有的测试用例都会调用该fixuture - 如果fixture有返回值,使用
@pytest.mark.usefixures()
无法获取到返回值,必须用传参的方式
将fixture名称作为测试用例函数的输入参数
- 代码
import pytest @pytest.fixture() def login(): print("this is login") def test_s1(login): print("this is test_s1")
- 结果
test_1.py::test_s1 ========this is login PASSED [100%] ========this is case 1
测试用例使用装饰器
-
代码1:usefixtures中可以放多个fixture参数,先执行的放前面,后执行的放后面
import pytest @pytest.fixture() def login(): print("this is login") @pytest.fixture() def login2(): print("this is login2") @pytest.mark.usefixures("login", "login2") def test_s1(): print("this is test_s1")
-
结果1:先执行
login()
,后执行login2()
test_1.py::test_s2 ========this is login ========this is login2 PASSED [100%] ========this is test_s2
-
代码2:可以叠加多个
@pytest.mark.usefixures()
,先执行的放底层,后执行的放上层import pytest @pytest.fixture() def login(): print("this is login") @pytest.fixture() def login2(): print("this is login2") @pytest.mark.usefixures("login2") @pytest.mark.usefixures("login") def test_s1(): print("this is test_s1")
-
结果2:先执行
login()
,后执行login2()
test_1.py::test_s2 ========this is login ========this is login2 PASSED [100%] ========this is test_s2
fixture设置autouse
- 代码:
import pytest @pytest.fixture(autouse=True) def login(): print("this is login") def test_s1(): print("this is test_s1")
- 结果:
test_1.py::test_s1 ========this is login PASSED [100%] ========this is test_s1
4、关于fixture实例化顺序
- fixture按照scope表示的顺序进行实例化的:
session
>package
>module
>class
>function
- 相同作用域的fixture会按照声明顺序进行实例化,如果fixture之间有依赖关系,会将依赖的fixture先实例化。
autouse=True
的fixture会在传参
或者装饰器
的fixture前实例化- 添加了
@pytest.fixture
,如果还想要依赖其他fixture,需要使用函数传参的方式,使用@pytest.mark.usefixtures()
的方式不生效 - 代码
import pytest order = [] @pytest.fixture(scope="session") def s(): order.append("s") @pytest.fixture(scope="module") def m(): order.append("m") @pytest.fixture() def f1(f3, a1): order.append("f1") @pytest.fixture() def f3(): order.append("f3") a = 123 yield a @pytest.fixture() def a1(): order.append("a1") @pytest.fixture() def f2(): order.append("f2") def test_order(f1, m, f2, s): print(order)
- 结果:
test_order(f1, m, f2, s)
执行顺序会按照s -> m -> f1 -> f2
test_1.py::test_order PASSED [100%] ['s', 'm', 'f3', 'a1', 'f1', 'f2']
5、fixture实现teardown功能
使用yield实现teardown功能
说明:
- 用fixture实现teardown不是一个独立的函数,而是由yield关键字开启
- 如果yield前面的代码,及setup部分已经抛出异常,就不会再执行yield后面的teardown部分
- 如果测试用例抛出异常,yield后面的teardown部分还是会正常执行
- 代码
import pytest @pytest.fixture(scope="session") def open(): # 会话前置操作 print("====打开浏览器====") test = "测试变量是否返回" yield test # 会话的后置操作 print("====关闭浏览器====") @pytest.fixture() def login(open): # 方法级别前置操作 print(f"====open返回值是: {open}====") username = "====我是账号====" password = "====我是密码====" yield username, password print("登录成功") def test_s1(login): print("====测试用例s1====") username, password = login print(username) print(password) def test_s2(login): print("====测试用例s2====") print(login)
- 结果
test_1.py::test_s1 ====打开浏览器==== ====open返回值是: 测试变量是否返回==== PASSED [ 50%] ====测试用例s1==== ====我是账号==== ====我是密码==== 登录成功 test_1.py::test_s2 ====open返回值是: 测试变量是否返回==== PASSED [100%] ====测试用例s2==== ('====我是账号====', '====我是密码====') 登录成功 ====关闭浏览器====
addfinalizer终结函数
说明
- 如下代码:如果
request.addfinalizer()
前面的setup部分抛出异常,则不会执行request.addfinalizer()
中的teardown内容 - 可以声明多个终结函数并调用
- 步骤:传入request参数;在fixture中定义一个内置函数;将定义的内置函数添加到request的addfinalizer中
- 代码
import pytest @pytest.fixture() def myfixture(request): print("====执行setup部分====") def fin(): print("====执行teardown部分====") request.addfinalizer(fin) def test_addfinalizer(myfixture): print("====执行用例====")
- 结果
test_1.py::test_addfinalizer ====执行setup部分==== PASSED [100%] ====执行用例==== ====执行teardown部分====