Pytest前置后置(夹具)
一、前言
在执行测试用例时,为了保证测试用例的稳定性,在执行用例前需要准备数据,然后用例执行完毕后,再销毁数据,这样能保证每次执行用例的结果一样,也就是所谓的幂等性。
对于pytest
测试框架,它提供了夹具的多种使用方法,其中有类似于unittest
的setUp()、tearDown()
,也有创新型的fixture
方法。具体如下:
二、pytest
之setup
1、module
作用域
setup_module
:在模块用例执行前运行一遍,其中的方法,一般使用得较少teardown_module
:在模块用例执行后再运行一遍,其中的方法,一般使用得较少
import pytest
def setup_module():
print("这是setup_module:在模块执行前运行一遍")
def teardown_module():
print("这是teardown_module:在模块执行后运行一遍")
class TestMyCode:
def setup_class(self):
print("这是setup_class:在类中使用,类执行之前运行一次")
def setup(self):
print("\n这是setup:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次")
def teardown(self):
print("\n这是teardown:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次")
def teardown_class(self):
print("这是teardown_class:在类中使用,类执行之后运行一次")
def test_setup_001(self):
print("==========执行测试用例:test_setup_001==========")
assert True
def test_setup_002(self):
print("==========执行测试用例:test_setup_002==========")
assert True
结果:
2、class
作用域
-
setup_class
:在类中使用,类中所有用例执行之前运行一次,其中的方法 -
teardown_class
:在类中使用,类中所有用例执行之后运行一次,其中的方法,比如
class TestMyCode:
def setup_class(self):
print("这是setup_class:在类中使用,类执行之前运行一次")
def setup_method(self):
print("\n这是setup_method:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次")
def teardown_method(self):
print("\n这是teardown_method:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次")
def teardown_class(self):
print("这是teardown_class:在类中使用,类执行之后运行一次")
def test_setup_001(self):
print("==========执行测试用例:test_setup_001==========")
assert True
def test_setup_002(self):
print("==========执行测试用例:test_setup_002==========")
assert True
结果:
3、function
作用域
-
setup_function
:不在类中使用,且只对类外的函数式测试用例生效 -
teardown_function
:不在类中使用,且只对类外的函数式测试用例生效,比如:
def setup_function():
print("这是setup_function:不在类中使用,且只对类外的函数式测试用例生效,在用例之前运行一遍")
def teardown_function():
print("这是teardown_function:不在类中使用,且只对类外的函数式测试用例生效,在用例执行之后运行一遍")
def test_setup_003():
print("==========执行类外的测试用例:test_setup_003==========")
assert True
结果:
4、method
作用域
setup_method
、teardown_method
:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次setup
、teardown
:在类中使用,在每一个方法之前执行一次,在每一个方法之后执行一次
三、pytest
之fixture
除了以上的方法之外,pytest
还提供了fixture
的方法,能更优雅的执行前置后置操作,将操作方法与用例相隔离,不过需要注意的是@pytest.fixture(scope="function")
中,scope
对应不通的值,fixture
方法作用域也不通,具体如下所示。
-
@pytest.fixture()
默认的级别为function
:在每一个用例方法之前执行一次yeild
前的方法,在用例执行完毕后再执行yeild
后的方法。注意:
@pytest.fixture()
与@pytest.fixture(scope="function")
相同。 -
@pytest.fixture(scope="class")
:在每一个类方法之前执行一次yeild
前的方法,在类中用例执行完后,再执行yeild
后的方法。 -
@pytest.fixture(scope="module")
:在每一个模块之前执行一次yeild
前的方法,在模块用例执行完后,再执行yeild
后的方法。 -
@pytest.fixture(scope="session")
:在每一个模块之前执行一次yeild
前的方法,在模块用例执行完后,再执行yeild
后的方法。
1、用例脚本中的fixture
方法
import pytest
def login():
print("\n这是登录操作")
def logout():
print("\n退出系统操作")
@pytest.fixture(scope="function")
def handle():
login()
yield "这是返回值"
logout()
class TestMyCode:
def test_setup_001(self, handle):
print("==========执行测试用例:test_setup_001==========")
print(handle)
assert True
def test_setup_002(self, handle):
print("==========执行测试用例:test_setup_002==========")
print(handle)
assert True
结果:
2、conftest
中的fixture
方法
通常做法是将fixture
方法统一放在conftest.py
文件中,用例与夹具方法隔离,更优雅,更容易管理。
#conftest.py
def login():
print("\n这是登录操作")
def logout():
print("\n退出系统操作")
@pytest.fixture(scope="function")
def handle():
login()
yield "这是返回值"
logout()
脚本文件:
#用例脚本文件
class TestMyCode:
def test_setup_001(self, handle):
print("==========执行测试用例:test_setup_001==========")
print(handle)
assert True
def test_setup_002(self, handle):
print("==========执行测试用例:test_setup_002==========")
print(handle)
assert True
结果:
四、pytest
之addfinalizer
在用例执行完毕后,还需要执行其他操作的,除了使用带有yield
的fixture
函数,还可以直接添加终结器addfinalizer
。
@pytest.fixture()
def clear_data(request):
print("\n这个fixture在每个case前执行一次")
def demo_finalizer2():
print("\n在每个case完成后执行的teardown2")
def demo_finalizer1():
print("\n在每个case完成后执行的teardown1")
#注册demo_finalizer为终结函数
request.addfinalizer(demo_finalizer1)
request.addfinalizer(demo_finalizer2)
class TestMyCode:
def test_setup_001(self, handle, clear_data):
print("==========执行测试用例:test_setup_001==========")
print(handle)
assert True
def test_setup_002(self, handle):
print("==========执行测试用例:test_setup_002==========")
print(handle)
assert True
从结果看出,与yield
是一致的。要注意的是,多个终结器的情况下,执行的顺序是与注册 request.addfinalizer
时候相反的。