pytest框架前后置处理

本文详细介绍了pytest框架中setup/teardown、setup_class/teardown_class以及@fixture装饰器的使用,展示了如何在自动化测试中管理浏览器操作和类级/函数级的初始化/清理工作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

pytest框架实现一些前后置(固件、夹具)的处理,常用三种

一、为什么需要前后置这些功能呢?

比如:web自动化执行用例之前,请问需要打开浏览器吗?用例执行后需要关闭浏览器吗?

二、setup和teardown

test_demo01.py

class TestDemo01:
    def setup(self):
        print("\n在执行测试用例之前执行的初始化代码:打开浏览器,加载网页")

    def test_01_sunwukong(self):
        print("\n测试孙悟空")

    def test_02_tangseng(self):
        print("\n测试唐僧")

    def teardown(self):
        print("\n在执行测试用例之后扫尾的代码:关闭浏览器")

all.py

import pytest

if __name__ == '__main__':
    pytest.main(["-vs", "./web_testCase/test_demo01.py"])

运行结果:
setup和teardown是在每个用例执行前后都会被执行

web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 
在执行测试用例之前执行的初始化代码:打开浏览器,加载网页

测试孙悟空
PASSED
在执行测试用例之后扫尾的代码:关闭浏览器

web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 
在执行测试用例之前执行的初始化代码:打开浏览器,加载网页

测试唐僧
PASSED
在执行测试用例之后扫尾的代码:关闭浏览器

三、setup_class、teardown_class

test_demo01.py


class TestDemo01:
    # 在所有的用例之前只执行一次
    def setup_class(self):
        print("\n在每个类执行前的初始化工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象")

    # 在每个用例之前执行一次
    def setup(self):
        print("\n在执行测试用例之前执行的初始化代码:打开浏览器,加载网页")

    def test_01_sunwukong(self):
        print("\n测试孙悟空")

    def test_02_tangseng(self):
        print("\n测试唐僧")

    def teardown(self):
        print("\n在执行测试用例之后扫尾的代码:关闭浏览器")

    def teardown_class(self):
        print("\n在每个类执行后的扫尾工作:比如:销毁日志对象,断开数据库连接")

all.py

import pytest

if __name__ == '__main__':
    pytest.main(["-vs", "./web_testCase/test_demo01.py"])

运行结果

web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 
在每个类执行前的初始化工作:比如:创建日志对象,创建数据库的连接,创建接口的请求对象

在执行测试用例之前执行的初始化代码:打开浏览器,加载网页

测试孙悟空
PASSED
在执行测试用例之后扫尾的代码:关闭浏览器

web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 
在执行测试用例之前执行的初始化代码:打开浏览器,加载网页

测试唐僧
PASSED
在执行测试用例之后扫尾的代码:关闭浏览器

在每个类执行后的扫尾工作:比如:销毁日志对象,断开数据库连接

四、使用@pytest.fixture()装饰器来实现部分用例的前后置

1、写法
@pytest.fixture(scope=,params=,autouse=,ids=,name=)
参数说明:
scope :表示的是被@pytest.fixture标记的方法的作用域。 【function:默认,class(类),module(模块),package/session】
params:参数化(支持:列表,元祖,字典列表[{},{},{}],字典元祖[(),(),()])
autouse:True:自动执行,默认False
ids:当 使用params参数化时,给每一个值设置一个变量名,意义不大
name:给表示的是被pytest.fixture标记的方法取一个别名
2、初级代码使用:

import pytest


@pytest.fixture(scope="function")
def my_fixture():
    print("这是前置方法")
    yield 
    print("这是后置方法")


class TestDemo01:

    def test_01_sunwukong(self):
        print("\n测试孙悟空")
     # 如果只让test_02  执行前后置,那么就只给这个方法设置my_fixture
    def test_02_tangseng(self, my_fixture):
        print("\n测试唐僧")

测试结果:

web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 
测试孙悟空
PASSED
web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 这是前置方法

测试唐僧
PASSED这是后置方法

3、scope不用参数值的区别
①function 函数级别,既每个函数执行,前后置方法也都会被执行

import pytest


@pytest.fixture(scope="function", autouse=True)
def my_fixture():
    print("这是前置方法")
    yield
    print("这是后置方法")


class TestDemo01:

    def test_01_sunwukong(self):
        print("\n测试孙悟空")

    def test_02_tangseng(self):
        print("\n测试唐僧")

测试结果

web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 这是前置方法

测试孙悟空
PASSED这是后置方法

web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 这是前置方法

测试唐僧
PASSED这是后置方法

②class 类级别,既 前后置方法只执行一次

import pytest


@pytest.fixture(scope="class", autouse=True)
def my_fixture():
    print("这是前置方法")
    yield
    print("这是后置方法")


class TestDemo01:

    def test_01_sunwukong(self):
        print("\n测试孙悟空")

    def test_02_tangseng(self):
        print("\n测试唐僧")

测试结果:
web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 这是前置方法

测试孙悟空
PASSED
web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 
测试唐僧
PASSED这是后置方法

③modle:模块级别

import pytest


@pytest.fixture(scope="module", autouse=True)
def my_fixture():
    print("这是前置方法")
    yield
    print("这是后置方法")


class TestDemo01:

    def test_01_sunwukong(self):
        print("\n测试孙悟空")

    def test_02_tangseng(self):
        print("\n测试唐僧")


class TestDemo02:
    def test_01_xiaoming(self):
        print("\n测试小明")

    def test_02_xiaohong(self):
        print("\n测试小红")

测试结果:
web_testCase/test_demo01.py::TestDemo01::test_01_sunwukong 这是前置方法

测试孙悟空
PASSED
web_testCase/test_demo01.py::TestDemo01::test_02_tangseng 
测试唐僧
PASSED
web_testCase/test_demo01.py::TestDemo02::test_01_xiaoming 
测试小明
PASSED
web_testCase/test_demo01.py::TestDemo02::test_02_xiaohong 
测试小红
PASSED这是后置方法

4、参数化使用: params

import pytest


@pytest.fixture(scope="function", params=['成龙', '吴京', '易烊千玺'])
def test_fixture(request):
    print("这是前置方法")
    yield request.param  # return和yeild的区别: 都是表示返回值的意思,但是return的后面不能有代码,yeild很后面可以有代码
    print("这是后置方法")
    # return


class TestDemo01:

    def test_01(self):
        print("\n测试用例1")

    # 如果只让test_02  执行前后置,那么就只给这个方法设置test_fixture

    def test_02(self, test_fixture):
        print("\n测试用例2")
        print(test_fixture)


if __name__ == '__main__':
    pytest.main(['-vs'])
 
 测试结果:
 test_demo01.py::TestDemo01::test_01 
测试用例1
PASSED
test_demo01.py::TestDemo01::test_02[\u6210\u9f99] 这是前置方法

测试用例2
成龙
PASSED这是后置方法

test_demo01.py::TestDemo01::test_02[\u5434\u4eac] 这是前置方法

测试用例2
吴京
PASSED这是后置方法

test_demo01.py::TestDemo01::test_02[\u6613\u70ca\u5343\u73ba] 这是前置方法

测试用例2
易烊千玺
PASSED这是后置方法

params=[‘成 ‘,‘甄子丹’,’ 10’]   params是参数名 有s。
request.param  是属性名 是没有s的。

5、ids参数的使用

import pytest


@pytest.fixture(scope="function", params=['成龙', '吴京', '易烊千玺'], ids=['cl', 'wj', 'yyqx'])
def test_fixture(request):
    print("这是前置方法")
    yield request.param  # return和yeild的区别: 都是表示返回值的意思,但是return的后面不能有代码,yeild很后面可以有代码
    print("这是后置方法")
    # return


class TestDemo01:

    def test_01(self):
        print("\n测试用例1")

    # 如果只让test_02  执行前后置,那么就只给这个方法设置test_fixture

    def test_02(self, test_fixture):
        print("\n测试用例2")
        print(test_fixture)


if __name__ == '__main__':
    pytest.main(['-vs'])

测试结果:
在这里插入图片描述
6、name参数的使用
当使用了别名之后,原来的名称就使用不了了。

import pytest


@pytest.fixture(scope="function", params=['成龙', '吴京', '易烊千玺'], ids=['cl', 'wj', 'yyqx'], name='fixture01')
def test_fixture(request):
    print("这是前置方法")
    yield request.param  # return和yeild的区别: 都是表示返回值的意思,但是return的后面不能有代码,yeild很后面可以有代码
    print("这是后置方法")
    # return


class TestDemo01:

    def test_01(self):
        print("\n测试用例1")

    # 如果只让test_02  执行前后置,那么就只给这个方法设置test_fixture

    def test_02(self, fixture01):
        print("\n测试用例2")
        print(fixture01)


if __name__ == '__main__':
    pytest.main(['-vs'])

五、通过conftest.py和@pytest.fixture()结合使用来实现全局的前置应用

1、应用场景:
比如:项目的全局登录,模块的全局处理
2、conftest.py的特点

①conftest.py文件是单独存放的一个夹具配置文件,名称是不能更改的。
②可以在不同的py文件中使用同一个fixture函数
③原则上conftest.py需要和运行的用例放到同一个目录下,并且不需要做任何的import导入操作。

代码实现:
在这里插入图片描述
每个模块设置单独的前后置,也可以使用外部公共的前后置。
product模块:
conftest.py

import pytest


@pytest.fixture(scope="function")
def product_fixture(request):
    print("商品管理前置方法")
    yield
    print("商品管理后置方法")

test_demo01.py

class TestDemo01:

    def test_01(self):
        print("\n测试用例1")

    # 如果只让test_02  执行前后置,那么就只给这个方法设置product_fixture

    def test_02(self, product_fixture):
        print("\n测试用例2")
        print(product_fixture)
   
 测试结果:
 web_testCase/product/test_demo01.py::TestDemo01::test_01 
测试用例1
PASSED
web_testCase/product/test_demo01.py::TestDemo01::test_02 商品管理前置方法

测试用例2
None
PASSED商品管理后置方法

在商品模块的用例中,也可以使用外部的前后置

import pytest


@pytest.fixture(scope="function")
def all_fixture(request):
    print("全局前置方法")
    yield
    print("全局后置方法")

test_demo01.py

class TestDemo01:

    def test_01(self):
        print("\n测试用例1")

    # 如果只让test_02  执行前后置,那么就只给这个方法设置product_fixture

    def test_02(self, all_fixture, product_fixture):
        print("\n测试用例2")
        print(all_fixture)
        print(product_fixture)

测试结果:
web_testCase/product/test_demo01.py::TestDemo01::test_01 
测试用例1
PASSED
web_testCase/product/test_demo01.py::TestDemo01::test_02 全局前置方法
商品管理前置方法

测试用例2
None
None
PASSED商品管理后置方法
全局后置方法

all.py

import pytest

if __name__ == '__main__':
    pytest.main(["-vs"])

六、pytest 的三种实现前后置方式的区别

  • setup/teardown ,setup_class/teardown_class,它是作用于所有的用例或类
  • @pytest.fixture() 它即可以全局前后置,也可以部门前后置
  • conftest.py 和@pytest.fixture()结合使用,作用于全局的前后置。
<think>我们正在讨论pytest中的setup和teardown方法,它们用于测试用例执行前后的初始化或清理工作。根据引用,pytest提供了不同级别的setup和teardown方法,包括模块级别、函数级别、类级别和方法级别。用户的问题是:我想了解pytest前后处理的级别,例如setup和teardown在不同范围内的应用。根据引用,我们可以总结如下:1.**模块级别(module)**:在整个模块(即一个.py文件)运行前后执行,只执行一次。-前置:`setup_module`-后:`teardown_module`2.**函数级别(function)**:只对不在类中的测试函数生效,每个函数用例执行前后都会执行。-前置:`setup_function`-后:`teardown_function`3.**类级别(class)**:在类中运行,整个类只运行一次(在类中所有用例之前和之后)。-前置:`setup_class`-后:`teardown_class`4.**方法级别(method)**:在类中每个测试方法(即类中的测试用例前后运行,每个方法都会执行一次。-前置:`setup_method`-后:`teardown_method`另外,引用[4]还提到了一种更通用的方式:`setup`和`teardown`(注意:在pytest中,通常使用`setup_method`和`teardown_method`来对应方法级别,而`setup`和`teardown`在pytest中通常等同于`setup_method`和`teardown_method`,但也可以用于函数级别?)。实际上,在pytest中,我们通常使用上述明确级别的方法。注意:在pytest中,还有一种称为“用例级别”的setup和teardown,即直接使用`setup`和`teardown`,它们可以在类中也可以在类外,但根据引用[4]的说明,它们在类中时相当于方法级别(即每个测试方法前后执行),在类外时相当于函数级别(即每个测试函数前后执行)。但是,在pytest中,更推荐使用`setup_method`和`teardown_method`来明确表示方法级别,而`setup_function`和`teardown_function`表示函数级别。为了更清晰地理解,我们可以参考引用[2]中的示例代码,它展示了各个级别的执行顺序。总结执行顺序(以引用[2]的示例代码为例):1.模块级别前置:`setup_module`(最先执行,整个模块只一次)2.类级别前置:`setup_class`(在类中,所有方法之前)3.方法级别前置:`setup_method`(在类中,每个测试方法之前)4.测试方法:例如`testA1`,`testA2`5.方法级别后:`teardown_method`(在类中,每个测试方法之后)6.类级别后:`teardown_class`(在类中,所有方法之后)7.函数级别前置:`setup_function`(不在类中的函数用例之前)8.测试函数:例如`testB1`,`testB2`9.函数级别后:`teardown_function`(不在类中的函数用例之后)10.模块级别后:`teardown_module`(整个模块最后执行,只一次)注意:模块级别的前置和后在整个模块的最开始和最后执行。类级别的前置在类中所有用例之前执行,后在类中所有用例之后执行。方法级别的前置在每个测试用例前后执行。函数级别的前置在每个测试函数(不在类中)前后执行。另外,pytest还支持更灵活的fixture机制,这是pytest中更推荐的方式,它可以替代setup/teardown,并且功能更强大(例如作用域scope,自动执行,参数化等)。但用户问题中明确询问的是setup/teardown,所以我们先回答这个。因此,我们可以按照级别来详细解释。回答结构:1.介绍pytest前后处理的级别。2.分别解释每个级别的作用和用法。3.提供示例代码片段(可选,但可以增强理解)。4.执行顺序总结。由于用户要求使用中文回答,并且要求结构清晰,我们按照级别逐一说明。</think>### pytest 前后处理级别详解 pytest 提供了多级 `setup` 和 `teardown` 方法,用于在不同范围内执行测试的初始化和清理工作。以下是各级别的详细说明: #### 1. **模块级别(module)** - **作用范围**:整个测试模块(`.py` 文件) - **执行时机**: - `setup_module`:文件内**第一个测试用例前**执行(仅一次) - `teardown_module`:文件内**所有测试完成后**执行(仅一次) - **适用对象**:全局资源(如数据库连接、临时文件) ```python def setup_module(): print("初始化模块资源") def teardown_module(): print("清理模块资源") ``` #### 2. **函数级别(function)** - **作用范围**:**类外部**的独立测试函数 - **执行时机**: - `setup_function`:**每个**函数用例**前**执行 - `teardown_function`:**每个**函数用例**后**执行 - **特点**:对类内部的测试方法**无效** ```python def setup_function(): print("函数级初始化") def test_example(): assert True def teardown_function(): print("函数级清理") ``` #### 3. **类级别(class)** - **作用范围**:整个测试类 - **执行时机**: - `setup_class`:类内**首个测试方法前**执行(仅一次) - `teardown_class`:类内**所有测试完成后**执行(仅一次) - **适用对象**:类共享资源(如浏览器实例) ```python class TestDemo: def setup_class(self): print("类级初始化") def teardown_class(self): print("类级清理") ``` #### 4. **方法级别(method)** - **作用范围**:类内部的**单个测试方法** - **执行时机**: - `setup_method`:**每个**测试方法**前**执行 - `teardown_method`:**每个**测试方法**后**执行 - **等价形式**:直接使用 `setup`/`teardown` 效果相同 ```python class TestDemo: def setup_method(self): print("方法级初始化") def test_case1(self): assert 1 + 1 == 2 def teardown_method(self): print("方法级清理") ``` --- ### 🚀 执行顺序总结 1. 模块级 `setup_module` → 类级 `setup_class` → 方法级 `setup_method` → **执行测试** → 方法级 `teardown_method` → 类级 `teardown_class` → 模块级 `teardown_module` 2. 函数级 `setup_function`/`teardown_function` **独立于类执行** 3. 嵌套执行遵循 **LIFO(后进先出)** 原则[^4] > **关键区别**: > - 模块/类级别:**一次性**初始化和清理 > - 函数/方法级别:**每条用例**前后执行 --- ### 相关问题 1. pytest 的 `fixture` 机制与传统的 `setup`/`teardown` 有何优势? 2. 如何控制不同级别 `setup`/`teardown` 的执行顺序? 3. 在分布式测试中,前后处理会遇到哪些挑战? [^1]: 模块、函数、类、方法级别的 setup 和 teardown 定义 [^2]: 多级前后方法的执行顺序示例 [^3]: 不同级别 setup/teardown 的作用范围说明 [^4]: 前后方法的执行顺序和 LIFO 原则
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值