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 标签化,回归 正向 ...
随机推荐
- 结对项目总结 -- 基于Qt开发的win10桌面应用
担任角色 在这次结对项目中,由于采用了我的个人项目作为参考,所以我继续担任后端开发的角色. 开发环境 前端采用Qt Creator4.13.2 (Community) 后端采用C++ 如何复用个人项目 ...
- 洛谷 P2629 好消息,坏消息(单调队列)
题目链接 首先想到的就是暴力前缀和,枚举一个区间每次统计前缀和,前缀和的某一个值为负数时就退出 如何枚举区间? 比如样例: \(4\) \(-3\ 5\ 1\ 2\) 可以使用一种断环为链的操作, 让 ...
- ES的基本语法
1 基本使用 使用kibaba来执行语句 es安装和kibaba安装:https://www.cnblogs.com/jthr/p/17075759.html 1)添加PUT 已存在会直接覆盖 PUT ...
- QQ、微信、微博、空间等分享链接接入
一.HTMl代码 1.隐藏标签用于获取信息 <img style="display:none" id="coverImage" src="@it ...
- 【源码】RapidJSON 源码剖析(0.1):调试工具 GDB 的使用
[源码]RapidJSON 源码剖析(0.1):调试工具 GDB 的使用 正式开始源码阅读之前,有必要了解一下源码阅读中用到的调试工具 GDB. GDB(GNU Debugger) 是一种可以运行在多 ...
- 手把手教你为基于Netty的IM生成自签名SSL/TLS证书
1.引言 对于IM聊天应用来说,为了提升安全性,对聊天消息加密是常规操作. 众所周之,Netty是高性能的Java NIO网络通信框架,因而用Netty来写IM是再正常不过了.网上关于为Netty生成 ...
- 有趣的python库-MyQR
MyQR-个性二维码 基本使用 from MyQR import myqr import os myqr.run( words="hu qing nian ni zhen bang, you ...
- Vulhub 漏洞学习之:Redis
Vulhub 漏洞学习之:Redis 1 Redis简介 Redis 是完全开源的,遵守 BSD 协议,是一个高性能的 key-value 数据库.Redis 与其他 key - value 缓存产品 ...
- Nacos集群搭建(三个节点)
Nacos集群安装 一,在每台服务器上安装nacos 1,准备安装包 github下载点 2,在/usr/local/目录下创建一个文件夹用于上传和解压Nacos cd /usr/local/ # ...
- git 合并dev分支到 master分支 (merge)
## 查看分支列表 $ git branch -a ## 切换到本地dev分支 $ git checkout dev ## 更新本地dev 分支 $ git pull ## 切换到master 分支 ...