前言
这篇文章开始,深入探究pytest
核心功能fixture
,感受pytest
的强大。
fixture是啥
fixture是pytest特有的功能,它用@pytest.fixture标识,定义在函数前面。在编写测试函数的时候,可以将此函数的名称作为传入参数,pytest会以依赖注入方式将该函数的返回值作为测试函数的传入参数。
基本依赖注入
例如,进行接口测试时,大部分功能需要登录才能使用,我们看看使用fixture
如何实现
import pytest
@pytest.fixture()
def login():
print("登录成功")
return 1
def test_01(login):
print("test_01执行")
assert login == 1
执行用例test_01
时,参数是login
,就开始从本用例中查找是否有这个参数或函数。找到login()的函数后,执行它,返回值传入test_01,之后再执行test_01测试函数。
注意:@pytest.fixture()中不带参数时范围默认scope="function"
销毁重置测试数据怎么做呢?
解决办法一: 使用yield
代替return
,改过的代码如下
import pytest
@pytest.fixture()
def login():
print("登录成功")
yield 1
print("后置步骤")
def test_01(login):
print("test_01执行")
assert login == 1
执行结果如下
登录成功
test_01执行
后置步骤
解决办法二: 使用addfinalizer
方法
import pytest
@pytest.fixture()
def login(request):
print("登录成功")
def add_finalizer():
print("后置步骤")
request.addfinalizer(add_finalizer)
return 1
def test_01(login):
print("test_01执行")
assert login == 1
执行结果和上面是一样的。fixture函数能够接收一个request参数,表示测试请求的上下文。使用request.addfinalizer方法为fixture添加清理销毁函数。
选择yield
还是addfinalizer
?
- addfinalizer可以注册多个终结销毁函数,而yield无法实现多个。
import pytest
@pytest.fixture()
def login(request):
print("登录成功")
def add_finalizer_01():
print("后置步骤01")
def add_finalizer_02():
print("后置步骤02")
request.addfinalizer(add_finalizer_01)
request.addfinalizer(add_finalizer_02)
return 1
def test_01(login):
print("test_01执行")
assert login == 1
执行结果如下
登录成功
test_01执行
后置步骤02
后置步骤01
可以看到注册的两个函数都被执行了,但是要特别注意执行顺序,可以看到,执行顺序与注册的顺序相反
不同层级scope
scope有5个级别参数function(默认)、class、module、package和session。
function
:每个函数或方法都会调用;class
:每个类调用一次,一个类可以有多种方法;module
:每个.py文件调用一次,该文件内又有多个function和class;·session
:多个文件调用一次,可以跨.py文件调用,每个.py文件就是module
执行下面代码,感受一下区别
import pytest
@pytest.fixture(scope="function")
def login():
print("登录成功")
return 1
def test_01(login):
print("test_01执行")
assert login == 1
def test_02(login):
print("test_02执行")
assert login == 1
scope="function"
时执行结果如下
登录成功
PASSED [ 50%]test_01执行
登录成功
PASSED [100%]test_02执行
scope="module"
时执行结果如下
登录成功
PASSED [ 50%]test_01执行
PASSED [100%]test_02执行
scope="class"
时,看下面这个例子
import pytest
@pytest.fixture(scope="class")
def login():
print("登录成功")
return 1
class TestClass:
def test_01(self, login):
print("test_01执行")
assert login == 1
def test_02(self, login):
print("test_02执行")
assert login == 1
输出结果为
登录成功
PASSED [ 50%]test_01执行
PASSED [100%]test_02执行
fixture为session级别是可以跨.py模块调用的,也就是当有多个.py文件用例的时候,如果多个用例只需调用一次fixture,那就可以设置为scope="session"。既然已经是跨模块,需要在.py模块之上。因此采用一个单独的文件conftest.py,文件名称是固定的,pytest会自动识别该文件。放到工程的根目录下就可以全局调用了,如果放到某个package包下,那就只在该package内有效。
conftest.py
import pytest
@pytest.fixture(scope="session")
def login():
print("登录成功")
return 1
test_demo01.py
class TestClass:
def test_01(self, login):
print("test_01执行")
assert login == 1
def test_02(self, login):
print("test_02执行")
assert login == 1
test_demo02.py
class TestClass02:
def test_01_c(self, login):
print("test_01_c执行")
assert login == 1
def test_02_c(self, login):
print("test_02_c执行")
assert login == 1
执行test_demo01.py
和test_demo02.py
会发现,登录成功只会打印一次。
自动调用fixture
上面我们使用fixture
都是通过传参的方式,这会改变原来测试方法的结构。那如何不通过注入的方式来使用呢?有2种方式可选.
方法一: 在fixture的参数中将autouse参数设置为True,这样便会自动应用所作用的范围。
import pytest
@pytest.fixture(autouse=True)
def login():
print("登录成功")
def test_01():
print("test_01执行")
def test_02():
print("test_02执行")
执行结果如下
登录成功
PASSED [ 50%]test_01执行
登录成功
PASSED [100%]test_02执行
可以看到,我们并没有将fixture
通过参数传入测试方法,而是将autouse参数设置为True,这样就会自动调用。
方法二: 使用@pytest.mark.usefixtures,在需要的测试方法上添加。
如果我们只有部分测试方法需要调用,想要更灵活一些,我们就可以选择方法二
import pytest
@pytest.fixture()
def login():
print("登录成功")
@pytest.mark.usefixtures("login")
def test_01():
print("test_01执行")
def test_02():
print("test_02执行")
我们只在test_01
方法使用了@pytest.mark.usefixtures("login")
,执行会发现只有test_01
才会执行login
方法中的内容。
最后
fixture
是pytest
的核心,对应内容也比较多,这篇内容主要介绍了fixture
基本使用、销毁数据实现、作用范围实例讲解、自动调用fixture
,下一篇内容会写关于fixture
并列嵌套使用以及重写fixture
相关内容。