下面就是“pytest自动化测试fixture的作用域实例化顺序及可用性”的完整攻略。
什么是fixture?
在pytest中,fixture是一种有助于实现测试自动化的机制。它是预先定义的一些可重用的代码块,主要用于提供测试执行所需的一些数据和环境。
通过fixture,我们可以将测试用例中的一些重复性工作抽象化为公共的API,并在各个测试用例中重复使用它,使得各个测试用例的代码更加简洁、易维护。
fixture的执行顺序、作用域、可用性等方面的配置对于测试设计和执行是非常重要的。
fixture的作用域(scope)
在pytest中,fixture可以设置作用域,以控制fixture的实例化和销毁的时机。通常用到的几种作用域有:
- function(默认):在每个测试用例函数执行前后执行,即每个测试用例函数均拥有一份fixture实例。
- class:在每个测试类执行前后执行,即每个测试类均拥有一份fixture实例。
- module:在每个测试模块执行前后执行,即每个测试模块均拥有一份fixture实例。
- session:在整个测试会话执行前后执行,即在整个测试会话中只有一份fixture实例。
我们可以在fixture装饰器的参数中设置作用域,如:
@pytest.fixture(scope='function')
def myfixture():
pass
fixture的实例化顺序
pytest在执行测试过程中,会按照一定的顺序实例化fixture。fixture可在名字相同的情况下,被多次声明和调用。pytest会优先调用匹配的fixture。
fixture实例化的顺序大致如下:
- function级别的fixture最先被实例化,这是因为每个测试用例函数都需要它。
- class级别的fixture其次被实例化,因为每个测试类也需要它。
- module级别的fixture再次被实例化,因为每个测试模块也需要它。
- session级别的fixture最后被实例化,因为整个测试会话只需使用一次。
fixture的可用性
fixture的可用性是指fixture在不同作用域的级别下,被调用和使用时的行为和实例状态。
- function级别的fixture:在每个测试用例函数执行前后执行一次,它的作用范围仅限于一个测试用例函数内。
- class级别的fixture:在每个测试类执行前后执行一次,它的作用范围限于整个测试类,即多个测试用例函数可以共享同一个fixture实例。
- module级别的fixture:在每个测试模块执行前后执行一次,它的作用范围限于整个测试模块,即整个测试模块内的多个测试类和测试用例函数可以共享同一个fixture实例。
- session级别的fixture:在整个测试会话执行前后执行一次,它的作用范围限于整个测试会话,即整个测试会话内的所有测试模块、测试类和测试用例函数都可以共享同一个fixture实例。
示例说明
下面用两个具体的示例说明fixture的使用和作用域,以及实例化顺序和可用性。
示例一:
假设我们实现了一个网站,需要在不同模块中对一些常用的功能进行测试,比如用户登陆、商品展示等。我们可以将这些功能的测试实现为_TEST_Login、_TEST_Products等类的方法。
我们可以先定义一些fixture,这些fixture需要会先于所有测试用例执行,用于在测试用例执行前准备数据。
如下面这些fixture:
import pytest
@pytest.fixture(scope='session')
def init_database():
print('Initialize Database')
# do something to initialize database
@pytest.fixture(scope='class')
def driver():
print('Initialize Driver')
# do something to initialize webdriver
yield
print('Quit Driver')
# do something to quit webdriver
在上述代码中,init_database()和driver()分别代表初始化数据库和webdriver。
测试用例可以分别在不同的测试模块(文件)中进行编写。如,我们可以在一个_TEST_Login模块中,实现用户登陆测试:
import pytest
@pytest.mark.usefixtures('init_database', 'driver')
class TestLogin():
def test_login_success(self):
"""测试正常登陆流程"""
# 测试代码
pass
def test_login_fail(self):
"""测试输入错误用户名和密码时登录操作"""
# 测试代码
pass
在上面的代码中,我们使用了上面声明的两个fixture:init_database和driver。我们使用usefixtures装饰器来声明使用这些fixture。在class级别的范围内,所有测试用例都可以共享driver这个fixture。init_database这个fixture具有最高级别的scope,整个测试会话只被实例化一次。
示例二:
在一些场景中,我们可能需要在测试用例函数内部,动态生成一些测试数据。比如,我们可以从excel文件、数据库或API获取一些数据,然后在测试用例中使用这些数据。这时,我们可以把数据获取和数据使用分成两个fixture。如下面这个例子:
import pytest
import requests
@pytest.fixture(scope='module')
def get_data():
response = requests.get('https://myapi.com/data')
data = response.json()
return data
@pytest.fixture
def use_data(get_data):
return get_data['user']
在上面代码中,我们定义了两个fixture。get_data会被module级别的用例函数调用,获取远程API中的数据;use_data在每个测试用例执行前都会被调用,获取get_data中的'user'字段。
接下来,我们可以在测试用例函数中使用这些fixture:
def test_myapi_data(use_data):
"""测试通过API获取的数据"""
# 使用use_data中的数据
assert use_data['age'] < 30
在上述代码中,use_data被作为参数传入测试用例函数,测试用例函数可以使用其中的数据。在这种写法中,fixture use_data没有设置scope参数,因此是默认的function(scope)。因为它是函数级别的,所以在每个测试函数前后都被调用,保证了在所有测试函数中,我们使用的数据都是相同的。
这两个示例展示了fixture在不同场景下的使用方式和作用域,可以供我们在实际开发中参考。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:pytest自动化测试fixture的作用域实例化顺序及可用性 - Python技术站