在 pytest 中,我们可以通过 conftest.py 文件来实现全局的前置和后置操作。
conftest.py 文件是一个特殊的 pytest 文件,它可以定义一些 fixture 和钩子函数,这些 fixture 和钩子函数可以在当前目录及其子目录下的所有测试文件中使用。
下面是一个例子,假设我们在一个名为 tests
的文件夹下编写了多个测试用例文件,我们希望在所有测试用例执行前和执行后都进行一些操作,可以在 tests
目录下创建一个名为 conftest.py
的文件,并定义两个 fixture 函数 global_setup
和 global_teardown
,代码如下:
import pytest
@pytest.fixture(scope='session')
def global_setup():
print("\n======= Global setup =======")
yield
print("\n======= Global teardown =======")
@pytest.fixture(scope='function')
def some_fixture():
print("Some fixture")
@pytest.fixture(scope='session')
def global_teardown():
print("\n======= Global cleanup =======")
在这个例子中,我们定义了两个 fixture 函数 global_setup
和 global_teardown
,它们的作用域分别是 session 和 function。global_setup
函数会在所有测试用例执行前被调用一次,global_teardown
函数会在所有测试用例执行后被调用一次。
注意,这里我们使用了 pytest 的 fixture 参数 scope
来指定 fixture 函数的作用域。scope
参数可以有四个值:
- function:fixture 函数的作用域为测试用例级别,每个测试用例执行前都会调用一次 fixture 函数;
- class:fixture 函数的作用域为测试类级别,每个测试类执行前都会调用一次 fixture 函数;
- module:fixture 函数的作用域为模块级别,即每个 Python 模块执行前都会调用一次 fixture 函数;
- session:fixture 函数的作用域为整个测试会话级别,即所有测试用例执行前都会调用一次 fixture 函数。
需要注意的是,fixture 函数的作用域不能超过其定义的文件的作用域。比如,在一个 pytest 测试文件中定义的 fixture 函数的作用域最大只能是 module,无法超过该文件的作用域。
接下来,在我们的测试用例文件中,我们可以通过传入 global_setup
和 global_teardown
fixture 来使用全局的前置和后置操作。例如:
def test_addition(some_fixture, global_setup, global_teardown):
assert 2 + 2 == 4
在这个例子中,我们将 global_setup
和 global_teardown
fixture 分别传入测试用例函数 test_addition
中,这样在执行测试用例前会先执行一次全局的前置操作,测试用例结束后会再执行一次全局的后置操作。需要注意的是,为了使 fixture 函数按照正确的顺序执行,我们将 global_setup
和 global_teardown
fixture 放在了 some_fixture
fixture 的后面。
这样就可以实现全局的前置和后置操作了。如果我们在 conftest.py
文件中定义了多个 fixture,那么这些 fixture 在所有测试用例中都可以被使用。同时,由于 pytest 的 fixture 可以被其他 fixture 所依赖,因此我们可以将多个 fixture 组合起来,实现更加复杂的测试场景。
在 pytest 中,我们可以通过 conftest.py 文件来实现全局的初始化操作。
conftest.py 文件是一个特殊的 pytest 文件,它可以定义一些 fixture 和钩子函数,这些 fixture 和钩子函数可以在当前目录及其子目录下的所有测试文件中使用。
下面是一个例子,假设我们在一个名为 tests
的文件夹下编写了多个测试用例文件,我们希望在所有测试用例执行前进行一些初始化操作,可以在 tests
目录下创建一个名为 conftest.py
的文件,并定义一个 fixture 函数 global_init
,代码如下:
import pytest
@pytest.fixture(scope='session', autouse=True)
def global_init():
print("\n======= Global initialization =======")
# 执行初始化操作
yield
print("\n======= Global cleanup =======")
# 执行清理操作
在这个例子中,我们定义了一个 fixture 函数 global_init
,它的作用域为 session,也就是整个测试会话期间只会被调用一次,且自动使用,不需要在测试用例中显式调用。
在 global_init
fixture 函数中,我们可以执行全局的初始化操作,例如读取配置文件、连接数据库等。在执行完初始化操作后,我们使用 yield 关键字将控制权交给后续的测试用例,等到所有测试用例执行完毕后,再回到 global_init
fixture 函数中,执行全局清理操作。需要注意的是,yield 语句前面的所有代码都是初始化操作,yield 语句后面的所有代码都是清理操作。
接下来,在我们的测试用例文件中,我们就可以直接使用全局初始化后的资源了。例如:
def test_addition():
assert 2 + 2 == 4
def test_subtraction():
assert 3 - 1 == 2
在这个例子中,我们没有显式地调用任何初始化函数,但是在执行测试用例前,global_init
fixture 函数会被自动调用,执行全局的初始化操作。测试用例执行完毕后,global_init
fixture 函数会再次被自动调用,执行全局的清理操作。
这样就可以实现全局的初始化操作了。如果我们在 conftest.py
文件中定义了多个 fixture,那么这些 fixture 在所有测试用例中都可以被使用。同时,由于 pytest 的 fixture 可以被其他 fixture 所依赖,因此我们可以将多个 fixture 组合起来,实现更加复杂的测试场景。
例如:
全局目录:
conftest.py内容
import pytest
@pytest.fixture(scope='session', autouse=True)
def global_init():
print("\n======= Global initialization =======")
# 执行初始化操作
yield
print("\n======= Global cleanup =======")
# 执行清理操作
局部初始化
import pytest
import allure
@pytest.fixture(scope='class')
def setup():
print("\n----------setup------------")
yield
print("\n---------Teardown---------")
array = [1,2,3,4]
@pytest.mark.parametrize("num", array)
class Test_fixtureModule():#Test开头,大写
@allure.feature("模块名称")
@allure.story("用户故事")
@allure.severity("Blocker") # 优先级,Blocker/Critical/Nomal/Minor/Trivial
@allure.description("描述内容")
def test_fixtureModule(self,num,setup):#test开头,小写
print(num)
assert 1 == 1
'''
============================= test session starts =============================
collecting ... collected 4 items
test_fixtureClass.py::Test_fixtureModule::test_fixtureModule[1]
======= Global initialization =======
----------setup------------
PASSED [ 25%]1
test_fixtureClass.py::Test_fixtureModule::test_fixtureModule[2] PASSED [ 50%]2
test_fixtureClass.py::Test_fixtureModule::test_fixtureModule[3] PASSED [ 75%]3
test_fixtureClass.py::Test_fixtureModule::test_fixtureModule[4] PASSED [100%]4
---------Teardown---------
======= Global cleanup =======
============================== 4 passed in 0.02s ==============================
Process finished with exit code 0
'''
import pytest
import allure
@pytest.fixture(scope='function')
def setup():
print("\n----------setup------------")
yield
print("\n---------Teardown---------")
array = [1,2,3,4]
@pytest.mark.parametrize("num", array)
class Test_fixtureFunction():#Test开头,大写
@allure.feature("模块名称")
@allure.story("用户故事")
@allure.severity("Blocker") # 优先级,Blocker/Critical/Nomal/Minor/Trivial
@allure.description("描述内容")
def test_fixtureFunction(self,num,setup):#test开头,小写
print(num)
assert 1 == 1
'''
============================= test session starts =============================
collecting ... collected 4 items
test_fixtureFunction.py::Test_fixtureFunction::test_fixtureFunction[1]
======= Global initialization =======
----------setup------------
PASSED [ 25%]1
---------Teardown---------
test_fixtureFunction.py::Test_fixtureFunction::test_fixtureFunction[2]
----------setup------------
PASSED [ 50%]2
---------Teardown---------
test_fixtureFunction.py::Test_fixtureFunction::test_fixtureFunction[3]
----------setup------------
PASSED [ 75%]3
---------Teardown---------
test_fixtureFunction.py::Test_fixtureFunction::test_fixtureFunction[4]
----------setup------------
PASSED [100%]4
---------Teardown---------
======= Global cleanup =======
'''
import pytest
import allure
@pytest.fixture(scope='module')
def setup():
print("\n----------setup------------")
yield
print("\n---------Teardown---------")
array = [1,2,3,4]
@pytest.mark.parametrize("num", array)
class Test_fixtureModule():#Test开头,大写
@allure.feature("模块名称")
@allure.story("用户故事")
@allure.severity("Blocker") # 优先级,Blocker/Critical/Nomal/Minor/Trivial
@allure.description("描述内容")
def test_fixtureModule(self,num,setup):#test开头,小写
print(num)
assert 1 == 1
'''
============================= test session starts =============================
collecting ... collected 4 items
..\ModelC\test_fixtureModule.py::Test_fixtureModule::test_fixtureModule[1]
======= Global initialization =======
----------setup------------
PASSED [ 25%]1
..\ModelC\test_fixtureModule.py::Test_fixtureModule::test_fixtureModule[2] PASSED [ 50%]2
..\ModelC\test_fixtureModule.py::Test_fixtureModule::test_fixtureModule[3] PASSED [ 75%]3
..\ModelC\test_fixtureModule.py::Test_fixtureModule::test_fixtureModule[4] PASSED [100%]4
---------Teardown---------
======= Global cleanup =======
'''
import pytest
import allure
@pytest.fixture(scope='session')
def setup():
print("\n----------setup------------")
yield
print("\n---------Teardown---------")
array = [1,2,3,4]
@pytest.mark.parametrize("num", array)
class Test_fixtureSession():#Test开头,大写
@allure.feature("模块名称")
@allure.story("用户故事")
@allure.severity("Blocker") # 优先级,Blocker/Critical/Nomal/Minor/Trivial
@allure.description("描述内容")
def test_fixtureSession(self,num,setup):#test开头,小写
print(num)
assert 1 == 1
'''
============================= test session starts =============================
collecting ... collected 4 items
test_fixtureSession.py::Test_fixtureSession::test_fixtureSession[1]
======= Global initialization =======
----------setup------------
PASSED [ 25%]1
test_fixtureSession.py::Test_fixtureSession::test_fixtureSession[2] PASSED [ 50%]2
test_fixtureSession.py::Test_fixtureSession::test_fixtureSession[3] PASSED [ 75%]3
test_fixtureSession.py::Test_fixtureSession::test_fixtureSession[4] PASSED [100%]4
---------Teardown---------
======= Global cleanup =======
============================== 4 passed in 0.01s ==============================
Process finished with exit code 0
'''