Pytest 固件
一、固件使用背景
在执行测试用例时,我们常常需要在测试用例执行的前后去完成一些额外的操作。例如针对于 Web 测试,在用例执行前需要打开浏览器,完成用户登录等一系列前置操作;在用例执行完成后,要清除浏览器缓存,关闭浏览器...... Pytest 框架提供的固件机制(又称为夹具)可以帮我们实现一系列的前后置操作。
我们先创建一套测试用例:

二、前后置函数
1. 测试方法级别
setup 和 teardown 方法作用于每一个测试方法,每个测试方法执行之前都会先去执行 setup 方法,执行之后都会再去执行 teardown 方法。
1 # cases/test_cases.py
2 class TestCase:
3
4 def setup(self):
5 print("\n测试方法执行前做对应的操作!!!")
6
7 def teardown(self):
8 print("\n测试方法执行后做对应的操作!!!")
9
10 def test_case_001(self):
11 print("模拟测试案例001")
12
13 def test_case_002(self):
14 print("模拟测试案例002")
15
16 def test_case_003(self):
17 print("模拟测试案例003")

需要注意的是:
如果前后置方法是定义在测试类内部的,那么作用的对象是当前测试类中的每一个测试方法,其他测试类和外部的测试方法将不会被影响。
1 # cases/test_cases.py
2 class TestCase:
3
4 def setup(self):
5 print("\n测试方法执行前做对应的操作!!!")
6
7 def teardown(self):
8 print("\n测试方法执行后做对应的操作!!!")
9
10 def test_case_001(self):
11 print("模拟测试案例001")
12
13 def test_case_002(self):
14 print("模拟测试案例002")
15
16 def test_case_003(self):
17 print("模拟测试案例003")
18
19
20 class TestCase2:
21 def test_case_004(self):
22 print("模拟测试案例004")
23
24 def test_case_005(self):
25 print("模拟测试案例005")
26
27
28 def test_outer_case():
29 print("模拟测试外部的测试方法")

如果前后置方法是定义在测试类外部的,那么作用的对象是定义在外部的测试方法,测试类中的测试方法不会被影响。
1 # cases/test_cases.py
2 def setup():
3 print("\n测试方法执行前做对应的操作!!!")
4
5
6 def teardown():
7 print("\n测试方法执行后做对应的操作!!!")
8
9 class TestCase:
10
11 def test_case_001(self):
12 print("模拟测试案例001")
13
14 def test_case_002(self):
15 print("模拟测试案例002")
16
17 def test_case_003(self):
18 print("模拟测试案例003")
19
20
21 class TestCase2:
22 def test_case_004(self):
23 print("模拟测试案例004")
24
25 def test_case_005(self):
26 print("模拟测试案例005")
27
28
29 def test_outer_case():
30 print("模拟测试外部的测试方法")

2. 测试类级别
setup_class 和 teardown_class 方法作用于当前的测试类,每个测试类执行之前都会先去执行 setup_class 方法,执行之后都会再去执行 teardown_class 方法。测试方法并不会受到这两个方法的影响。
1 # cases/test_cases.py
2 class TestCase:
3
4 def test_case_001(self):
5 print("模拟测试案例001")
6
7 def test_case_002(self):
8 print("模拟测试案例002")
9
10 def test_case_003(self):
11 print("模拟测试案例003")
12
13
14 class TestCase2:
15 def setup_class(self):
16 print("\n测试方法执行前做对应的操作!!!")
17
18 def teardown_class(self):
19 print("\n测试方法执行后做对应的操作!!!")
20
21 def test_case_004(self):
22 print("模拟测试案例004")
23
24 def test_case_005(self):
25 print("模拟测试案例005")

三、装饰器实现
使用前后置函数的方式作用的对象都是一个模块内或者是一个测试类中的全体对象,没有办法做到只作用于部分对象。Pytest 提供了 @pytest.fixture() 方法来实现部分用例的前后置操作。
1. 简单使用
第一步,先自定义一个生成器方法
1 def my_fixture():
2 print("前置操作")
3 yield
4 print("后置操作")
第二步,添加装饰器方法
1 import pytest
2
3 @pytest.fixture()
4 def my_fixture():
5 print("前置操作")
6 yield
7 print("后置操作")
第三步,将函数名作为参数,传递给需要做前后置操作的测试方法。测试方法在执行前会先去执行生成器函数中
yield的前半部分代码;测试方法执行完成后,会去执行生成器函数中yield的后半部分代码。
1 # cases/test_cases.py
2 import pytest
3
4 @pytest.fixture()
5 def my_fixture():
6 print("前置操作")
7 yield
8 print("后置操作")
9
10 class TestCase:
11
12 def test_case_001(self, my_fixture):
13 print("模拟测试案例001")
14
15 def test_case_002(self):
16 print("模拟测试案例002")
17
18 def test_case_003(self):
19 print("模拟测试案例003")

2. 相关参数详解
2.1 autouse
值为 True 时,表示固件自动执行,即不需要在对应的测试方法中引用也会触发,默认值为 False
1 # cases/test_cases.py
2 import pytest
3
4 @pytest.fixture(autouse=True)
5 def my_fixture():
6 print("\n前置操作")
7 yield
8 print("\n后置操作")
9
10
11 class TestCase:
12 # 并未传入固件使用
13 def test_case_001(self):
14 print("模拟测试案例001")
15
16 def test_case_002(self):
17 print("模拟测试案例002")
18
19 def test_case_003(self):
20 print("模拟测试案例003")

2.2 scope
表示的是被 @pytest.fixture 标记的方法的作用域,有以下几个值:
function:作用于测试方法级别,每个函数或方法都会调用
1 # cases/test_cases.py
2 import pytest
3
4 @pytest.fixture(scope="function", autouse=True)
5 def my_fixture():
6 print("\n前置操作")
7 yield
8 print("\n后置操作")
9
10
11 class TestCase:
12
13 def test_case_001(self):
14 print("模拟测试案例001")
15
16 def test_case_002(self):
17 print("模拟测试案例002")
18
19 def test_case_003(self):
20 print("模拟测试案例003")

class:作用于测试类级别,测试类执行时会执行一次固件
1 # cases/test_cases.py
2 import pytest
3
4 @pytest.fixture(scope="class", autouse=True)
5 def my_fixture():
6 print("\n前置操作")
7 yield
8 print("\n后置操作")
9
10 class TestCase:
11
12 def test_case_001(self):
13 print("模拟测试案例001")
14
15 def test_case_002(self):
16 print("模拟测试案例002")
17
18 def test_case_003(self):
19 print("模拟测试案例003")
20
21 class TestCase2:
22
23 def test_case_004(self):
24 print("模拟测试案例004")
25
26 def test_case_005(self):
27 print("模拟测试案例005")

module:作用于测试模块,测试模块(即
py文件)执行时会执行一次固件

session:作用于会话,可以跨多个
.py文件,若多个模块中的用例都调用了 fixture,只会运行一次
1 ####################### cases/test_cases.py ########################
2 import pytest
3
4 @pytest.fixture(scope="session", autouse=True)
5 def my_fixture():
6 print("\n前置操作")
7 yield
8 print("\n后置操作")
9
10 class TestCase:
11
12 def test_case_001(self):
13 print("模拟测试案例001")
14
15 def test_case_002(self):
16 print("模拟测试案例002")
17
18 def test_case_003(self):
19 print("模拟测试案例003")
20
21 ####################### cases/test_cases_2.py ##############################
22 class TestCase2:
23
24 def test_case_004(self):
25 print("模拟测试案例004")
26
27 def test_case_005(self):
28 print("模拟测试案例005")

2.3 params
使用装饰器方的固件,还可以进行参数传递。参数的类型支持以下四种:
列表
元组
字典列表:[{},{},{}]
字典元组:({},{},{})
我们先打印一下测试方法中接收的固件名的值是啥
1 import pytest
2
3 @pytest.fixture(scope="function")
4 def my_fixture():
5 print("一些操作......")
6
7 class TestCase:
8
9 def test_case_001(self, my_fixture):
10 print(f"模拟测试案例001----{my_fixture}")
11
12 def test_case_002(self):
13 print("模拟测试案例002")
14
15 def test_case_003(self):
16 print("模拟测试案例003")

在固件中我们尝试返回一个值试试:
1 import pytest
2
3 @pytest.fixture(scope="function")
4 def my_fixture():
5 print("一些操作......")
6 return "success"
7
8 class TestCase:
9
10 def test_case_001(self, my_fixture):
11 print(f"模拟测试案例001----{my_fixture}")
12
13 def test_case_002(self):
14 print("模拟测试案例002")
15
16 def test_case_003(self):
17 print("模拟测试案例003")

可见在测试方法中传入固件名,除了可以执行固件对应的操作,还可以拿到固件的返回值。那么想结合 params 参数在固件中传值就十分容易了:
1 import pytest
2
3 @pytest.fixture(scope="function", params=["aaa", "bbb", "ccc"])
4 def my_fixture(request): # 固定写法,使用参数时必须接收一个request变量
5 print("一些操作......")
6 return request.param # 固定写法,返回参数
7
8 class TestCase:
9
10 def test_case_001(self, my_fixture):
11 print(f"模拟测试案例001----{my_fixture}")
12
13 def test_case_002(self):
14 print("模拟测试案例002")
15
16 def test_case_003(self):
17 print("模拟测试案例003")

被标记的测试方法被执行了三次,是因为传的参数有三个值,每执行一次就会传一个值过去。
如果固件要执行前后置操作,就不能用 return 返回值了,要使用 yield:
1 import pytest
2
3 @pytest.fixture(scope="function", params=["aaa", "bbb", "ccc"])
4 def my_fixture(request): # 固定写法,使用参数时必须接收一个request变量
5 print("前置操作......")
6 yield request.param # 固定写法,返回参数
7 print("后置操作......")
8
9 class TestCase:
10
11 def test_case_001(self, my_fixture):
12 print(f"模拟测试案例001----{my_fixture}")
13
14 def test_case_002(self):
15 print("模拟测试案例002")
16
17 def test_case_003(self):
18 print("模拟测试案例003")
2.4 ids
当固件使用 params 进行传值时,给每一个参数值设置一个单独的 id(意义不是很大)
1 import pytest
2
3 @pytest.fixture(scope="function", params=["aaa", "bbb", "ccc"], ids=["parm_1", "parm_2", "parm_3"])
4 def my_fixture(request): # 固定写法,使用参数时必须接收一个request变量
5 print("前置操作......")
6 yield request.param # 固定写法,返回参数
7 print("后置操作......")
8
9 class TestCase:
10
11 def test_case_001(self, my_fixture):
12 print(f"模拟测试案例001----{my_fixture}")
13
14 def test_case_002(self):
15 print("模拟测试案例002")
16
17 def test_case_003(self):
18 print("模拟测试案例003")

2.5 name
给标记的固件方法起一个别名,后续传参都使用该别名。
1 import pytest
2
3 @pytest.fixture(scope="function", name="init")
4 def my_fixture():
5 print("前置操作......")
6 yield
7 print("后置操作......")
8
9 class TestCase:
10 # 测试方法中传参不再是固件函数的名字,而是别名
11 def test_case_001(self, init):
12 print(f"模拟测试案例001")
13
14 def test_case_002(self):
15 print("模拟测试案例002")
16
17 def test_case_003(self):
18 print("模拟测试案例003")
注意:一旦使用别名,就不能再使用原来的函数名作为参数传递了,否则会报错。
1 import pytest
2
3 @pytest.fixture(scope="function", name="init")
4 def my_fixture():
5 print("前置操作......")
6 yield
7 print("后置操作......")
8
9 class TestCase:
10 # 固件方法起了别名init,但是测试方法中仍然使用原固件函数名my_fixture作为参数传参
11 def test_case_001(self, my_fixture):
12 print(f"模拟测试案例001")
13
14 def test_case_002(self):
15 print("模拟测试案例002")
16
17 def test_case_003(self):
18 print("模拟测试案例003")

四、conftest.py 实现
为了避免代码的冗余,测试用例公共的前后置操作往往会抽离出来而不是重复写在每个用例之中。在 pytest 中,全局公共的前后置操作要求写在一个名为 conftest.py 的文件中。该文件主要有以下特点:
conftest.py文件是单独存放的一个夹具配置文件,且文件名不能更改,必须是这个名字;conftest.py常常和fixture装饰器联合使用,实现测试项目用例全局的前后置操作,且定义在conftest.py中的固件函数可以被不同的 py 文件引用;原则上,
conftest.py文件需要和执行的用例放在同一层级上(实际上也可以放到其他目录中),且不需要做任何的import操作。
下面我们就用几个实际的示例来感受以下 conftest.py 的强大:
首先,我们创建一套测试用例环境:

我们先忽略conftest.py ,还是按照一开始使用装饰器定义固件的方式创建用例:
1 ############# product/test_product.py #############
2 import pytest
3
4 @pytest.fixture(name="init_product")
5 def init():
6 print("\n产品测试前置操作....")
7 yield
8 print("\n产品测试后置操作....")
9
10 def test_product_case(init_product):
11 print("模拟产品测试......")
12
13
14 ############# user/test_user.py ##################
15 import pytest
16
17 @pytest.fixture(name="init_user")
18 def init():
19 print("\n用户测试前置操作....")
20 yield
21 print("\n用户测试后置操作....")
22
23 def test_user_case(init_user):
24 print("模拟用户测试......")
此时,我们尝试在两个测试用例里面分别调用对方用例中的固件函数:
1 ############# product/test_product.py #############
2 import pytest
3
4 @pytest.fixture(name="init_product")
5 def init():
6 print("\n产品测试前置操作....")
7 yield
8 print("\n产品测试后置操作....")
9
10 def test_product_case(init_product,init_user):
11 print("模拟产品测试......")
12
13
14 ############# user/test_user.py ##################
15 import pytest
16
17 @pytest.fixture(name="init_user")
18 def init():
19 print("\n用户测试前置操作....")
20 yield
21 print("\n用户测试后置操作....")
22
23 def test_user_case(init_user,init_product):
24 print("模拟用户测试......")

结果是显而易见的,由于固件不是定义在当前的 py 文件中的,跨 py 文件引用且不导入,肯定报错。接下来我们将每个模块的固件分别迁移到各自的 conftest.py 下:
1 ############# product/conftest.py #############
2 import pytest
3
4 @pytest.fixture(name="init_product")
5 def init():
6 print("\n产品测试前置操作....")
7 yield
8 print("\n产品测试后置操作....")
9
10
11 ############# product/test_product.py #############
12 def test_product_case(init_product):
13 print("模拟产品测试......")
14
15
16
17 ############# user/conftest.py ##################
18 import pytest
19
20 @pytest.fixture(name="init_user")
21 def init():
22 print("\n用户测试前置操作....")
23 yield
24 print("\n用户测试后置操作....")
25
26
27 ############# user/test_user.py ##################
28 def test_user_case(init_user):
29 print("模拟用户测试......")

执行用例通过,可见测试用例在执行时会去自己模块下的 conftest.py 中寻找对应的固件执行。当然,此时想要调用对方的固件还是没法调用的:
1 ############# product/test_product.py #############
2 def test_product_case(init_product, init_user):
3 print("模拟产品测试......")
4
5
6 ############# user/test_user.py ##################
7 def test_user_case(init_user, init_product):
8 print("模拟用户测试......")

要想实现可以全局调用,可以将两个模块中的固件方法迁移到根目录下的 conftest.py 中:
1 # 根目录下的 conftest.py
2 import pytest
3
4 @pytest.fixture(name="init_product")
5 def product_init():
6 print("\n产品测试前置操作....")
7 yield
8 print("\n产品测试后置操作....")
9
10
11 @pytest.fixture(name="init_user")
12 def user_init():
13 print("\n用户测试前置操作....")
14 yield
15 print("\n用户测试后置操作....")
此时,我们尝试在两个测试用例里面分别调用对方用例中的固件函数:
1 ############# product/test_product.py #############
2 def test_product_case(init_product, init_user):
3 print("模拟产品测试......")
4
5
6 ############# user/test_user.py ##################
7 def test_user_case(init_user, init_product):
8 print("模拟用户测试......")

执行用例通过,且固件执行的顺序取决于固件名参数在测试方法中传参的位置,先传入的就先执行。
Pytest 固件的更多相关文章
- pytest测试框架 -- assert断言和fixture固件
一.断言 (1)使用assert语句进行断言 # test_run.py @pytest.mark.assert def test_assert(self): r = requests.get(&qu ...
- pytest(6)-Fixture(固件)
什么是固件 Fixture 翻译成中文即是固件的意思.它其实就是一些函数,会在执行测试方法/测试函数之前(或之后)加载运行它们,常见的如接口用例在请求接口前数据库的初始连接,和请求之后关闭数据库的操作 ...
- 2.pytest前后置(固件、夹具)处理
一.setup/teardown/setup_calss/teardown_class 为什么需要这些功能? 比如:我们执行用例之前,需要做的哪些操作,我们用例执行之后,需要做哪些操作 # 在所有用例 ...
- pytest 2.测试用例setup和teardown
之前我写的unittest的setup和teardown,还有setupClass和teardownClass(需要配合@classmethod装饰器一起使用),接下来就介绍pytest的类似于这类的 ...
- python:pytest中的setup和teardown
原文:https://www.cnblogs.com/peiminer/p/9376352.html 之前我写的unittest的setup和teardown,还有setupClass和teardow ...
- pytest使用总结笔记
简介 pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高.并且pytest兼容unittest的用例,支 ...
- 《带你装B,带你飞》pytest修仙之路5 - yield操作
1. 简介 上一篇中,我们刚刚实现了在每个用例之前执行初始化操作,那么用例执行完之后如需要清除数据(或还原)操作,可以使用 yield 来实现.fixture通过scope参数控制setup级别,既然 ...
- Pytest单元测试框架-学习
pytest: Python的一个单元测试框架,基于UnitTest二次开发,语法上更加简洁,可以用来做Python开发项目的单元测试,UI自动化.接口自动化测试等,有很多的插件访问Pytest插件汇 ...
- python单元测试框架pytest
首先祝大家国庆节日快乐,这个假期因为我老婆要考注会,我也跟着天天去图书馆学了几天,学习的感觉还是非常不错的,这是一篇总结. 这篇博客准备讲解一下pytest测试框架,这个框架是当前最流行的python ...
- pytest使用小结
一.pytest简洁和好处 自动发现测试用例 testloader 断言方便 ,自定义错误提示 assert 正则匹配 灵活运行指定的测试用例,指定模块,制定测试类,测试用例 -k 标签化,回归 正向 ...
随机推荐
- day08-AOP-01
AOP 1.官方文档 AOP讲解:下载的spring文件-->spring-framework-5.3.8/docs/reference/html/core.html#aop AOP APIs: ...
- Java后台如何接收与处理JSON类型数据
项目开发中偶尔会使用到某个为JSON类型的字段,一个字段中又包含多个其他的字段. 这种设计方式是根据实际需要来进行处理的,比如规则可能包含多条,每一条规则又包含 多个字段:再比如一些特殊的应用场景如标 ...
- DVWA靶场实战(十二)——XSS(Stored)
DVWA靶场实战(十二) 五.XSS(Stored): 1.漏洞原理: XSS的Stored被称作存储型XSS漏洞,漏洞的原理为语句被保存到服务器上,显示到HTML页面中,经常出现在用户评论的页面,攻 ...
- ATM项目开发
目录 一.项目开发流程 1.项目需求分析: 2.项目架构设计: 3.项目分组开发: 4.项目提交测试: 5.项目交付上线: 二.项目需求分析 1.主题 2.项目核心 3.项目需求: 4.从需求中提炼出 ...
- Vue34 VueX
1 简介 Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式 + 库.它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化. vue官方搭配,专属使用 ...
- PowerToys 微软效率工具包 使用教程
今天给大家介绍一款 非常实用的微软工具包 里面包含 快捷键的使用 颜色选择器 键盘管理器 屏幕标尺 鼠标实用工具等众多高效工作的功能 还是蛮出彩的 下载 PowerToys⇲ 安装教程 1.双击文件运 ...
- 不花钱几分钟让你的站点也支持https
前言 现在,免费SSL证书已经很普遍了,但是,申请和配置SSL证书仍然是一件较为繁琐的事,修改web服务配置在所难免,且不同的web服务配置方法不一样,不具备通用性.本文介绍一种通用的快速配置方法,w ...
- RocketMQ - 生产者原理
https://rocketmq.apache.org/ Apache RocketMQ是一款开源的.分布式的消息投递与流数据平台.出生自阿里巴巴,在阿里巴巴内部经历了3个版本后,作为Apache 顶 ...
- 转载:屎人-->诗人系列--码农之歌
转贴经常关注的一个博主的文,感觉还挺有趣: https://goofegg.github.io/content.html?id=141 ************************** 这个系列第 ...
- 华为云API Arts:用“1+1+5”的模式,为你带来API-First体验
摘要:华为云API Arts是API全生命周期一体化协作平台,支持开发者一站式高效实现API设计.API开发.API测试.API托管.API运维.API变现,助力企业数字化转型. 本文分享自华为云社区 ...