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 标签化,回归 正向 ...
随机推荐
- 反射_Class对象功能_获取Constructor-反射_Class对象功能_获取Method
反射_Class对象功能_获取Constructor Constructor<?>[] getConstructors() Constructor<T> getConstruc ...
- Git【初次提交内容(代码)到新创建的远端仓库】
哈喽大家好,转眼到了年后了.年都过完了,就要开始工作了啊.那今天给大家带来的是(题目).因为从实习期开始,就一直用SVN,即使是使用Git的时候,也用了Sourcetree工具.直到最近打算和朋友(兮 ...
- 使用 flexible.js + rem 制作苏宁移动端首页
一.技术选型 二.搭建相关文件夹 三.设置视口标签以及引入初始化样式文件和js文件 四.body 样式 五.rem 适配方案二 body样式修改 index.css body { min-width: ...
- 简述 JavaScript 的执行机制
一.单线程 为了解决这个问题,防止下一个任务等待上一个任务等待太长的时间,所以提出了 Web Worker标准,允许 JS 创建多个线程,于是JS出现了同步 和 异步 ,异步就是可以同时进行多个任务, ...
- LM算法详解
1. 高斯牛顿法 残差函数f(x)为非线性函数,对其一阶泰勒近似有: 这里的J是残差函数f的雅可比矩阵,带入损失函数的: 令其一阶导等于0,得: 这就是论文里常看到的normal equation. ...
- 最大K段和
题目大意 有一个长度为 \(N\) 的序列 \(A\) .他希望从中选出不超过 \(K\) 个连续子段,满足它们两两不相交,求总和的最大值(可以一段也不选,答案为 \(0\)). 分析 很容易想到 \ ...
- cdq 分治学习笔记
CDQ 分治是一种很玄学的东西. Part 0 引子 相信大家都会归并排序,又都知道归并排序求逆序对怎么求的 如果连归并求逆序对都不会那你为什么要学 cdq 分治阿喂 void merge_sort( ...
- JavaSE 对象与类(一)
对象与类 1.面向对象程序概述 Java是完全面向对象的,必须熟悉OOP才能够编写Java程序. 概念:类class.实例(对象)instance 由类构造(construct)对象的过程称为创建类的 ...
- jsHtml解码
//将HTML代码转换为文本 function HTMLDecode(text) { var temp = document.createElement("div"); temp. ...
- select省市联动+对应经销商、自定义箭头
HTML: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <met ...