http://doc.pytest.org/en/latest/fixture.html
fixture的优点
显式、模块化、可扩展
- fixture具有明确的名称,并通过从测试功能,模块,类或整个项目中声明它们的使用来激活。
- fixture以模块化方式实现,因为每个fixture名称触发fixture功能,该fixture功能本身可以使用其他fixture。
- fixture管理从简单的单元扩展到复杂的功能测试,允许根据配置和组件选项对夹具和测试进行参数化,或者在功能,类,模块或整个测试会话范围内重复使用夹具。
fixture作为函数参数
import pytest
@pytest.fixture(scope="session")
def start():
print("fixture-start开始")
def test_3(start):
print("结束")
执行结果:我们可以发现test_3被执行前 先执行了start方法
image.png
执行逻辑:
image.png
在
@pytest.fixture(scope="session")
中我们我们写有scope="session",那么这个参数的作用是什么呢?这个我们在后面的【fixture的执行顺序控制】中讲到
fixture的模块化
在使用中如果发现需要使用多个文件中的fixture,则可以将fixture写入conftest.py中。
使用时不需要导入要在测试中使用的fixture,它会自动被pytest发现。
查找顺序:
fixture功能的发现从测试类开始,然后是测试模块,然后是 conftest.py文件,最后是内置和第三方插件
#conftest.py
import pytest
@pytest.fixture(scope="session")
def start():
print("fixture-start开始")
#test_fixtures2.py
def test_3(start):
print("结束")
执行结果一致
image.png
可以使用
pytest --fixtures test_fixtures2.py
查看可用的fixture
------------------- fixtures defined from test.conftest --------------------
topics
conftest.py:11: no docstring available
start [session scope]
conftest.py:7: no docstring available
===================== no tests ran in 0.02 seconds =========================
fixture的执行顺序控制
前面我们提到在@pytest.fixture(scope="session")
中的scope参数,scope的作用是有多个fixture时指定优先级
scope从低到高优先级:function(默认)、class、module、package(实验,有风险)、session。
import pytest
# fixtures documentation order example
order = []
@pytest.fixture(scope="session")
def s1():
order.append("s1")
@pytest.fixture(scope="module")
def m1():
order.append("m1")
@pytest.fixture(scope="class")
def c1():
order.append("c1")
@pytest.fixture()
def f3():
order.append("f3")
class TestA():
def test_order(self, c1, s1, m1,f3):
print(order)
assert order == ["s1", "m1", "c1", "f3"]
执行结果:我们可以发现执行顺序取决于fixture的scope传参image.png
设置默认执行的fixture
对于所有test_方法都要使用的fixture,我们在定义fixture时可以使用autouse=True
,就可以不传参了
@pytest.fixture()
def f3():
order.append("f3")
@pytest.fixture(autouse=True) #设置的默认执行
def a1():
order.append("a1")
def test_1(f3):
print(order)
assert order == ["a1", "f3"]
执行结果:我们在test_1方法中没有传a1,但仍然执行了image.png
fixture的嵌套
如果一个fixture执行前需要先执行另一个fixture,我们可以使用嵌套来解决
@pytest.fixture
def f1(f3):
order.append("f1")
@pytest.fixture()
def f3():
order.append("f3")
def test_1(f1):
print(order)
assert order == ["f3", "f1"]
执行结果:image.png
fixture做后置处理yield
在pytest中我们有teardown_module之类的后置处理,fixture也可以支持相关操作
import pytest
@pytest.fixture()
def f1():
print("f1")
yield f1
print("f1 后置处理")
class TestA():
def test_1(self,f1):
print("test_1")
assert 2 == 1
可以看见在test_1()执行后,执行了yield
后面的语句。且无论用例是否执行成功
image.png
- 注意:如果我们使用有
scope="class"
的fixture,则会在类执行完成后进行后置处理,其他的scope参数也一样
通过request.module
获取请求的module属性
@pytest.fixture(scope="module")
def smtp(request):
server = getattr(request.module, "smtpserver")
print(server)
yield smtp
pass
smtpserver = "mail.python.org"
class TestA():
def test_showhelo(self,smtp):
pass
执行结果:fixture通过request.module
将smtpserver取了出来
image.png
官网说还可以将类属性取出来,但没找到关键字
fixture的参数化
需要使用params
参数进行参数化,然后通过request.param
取出
- 单个参数的参数化
@pytest.fixture(params=['a', 'v', 'c'])
def fix(request):
return request.param
def test_9(fix):
print(fix)
执行结果:将三个参数依次取出image.png
- 多个参数的参数化----使用list
list = [{'a': '阿斯顿', 'b': '请问'},{'a': '自行车', 'b': '出现在'}]
@pytest.fixture(params=list)
def dic(request):
return request.param
def test_2(dic):
print('a=' + dic["a"])
print('b=' + dic["b"])
执行结果:image.png
另外fixture还支持mock
https://www.jianshu.com/p/4bd41d6bb2a9