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

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("模拟测试外部的测试方法")

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 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")

值为 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")

表示的是被 @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")

使用装饰器方的固件,还可以进行参数传递。参数的类型支持以下四种:
列表
元组
字典列表:[{},{},{}]
字典元组:({},{},{})
我们先打印一下测试方法中接收的固件名的值是啥
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")
当固件使用 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")

给标记的固件方法起一个别名,后续传参都使用该别名。
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")

为了避免代码的冗余,测试用例公共的前后置操作往往会抽离出来而不是重复写在每个用例之中。在 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是一个非常成熟的全功能的Python测试框架,主要有以下几个特点:简单灵活,容易上手支持参数化能够支持简单的单元测试和复杂的功能测试,还可以用来做selenium/appnium等自动化测试、接口自动化测试(pytest+requests)pytest具有很多第三方插件,并且可以自定义扩展,比较好用的如pytest-selenium(集成selenium)、pytest-html(完美html测试报告生成)、pytest-rerunfailures(失败case重复执行)、pytest-xdist(多CPU分发)等测试用例的skip和xfail处理可以很好的和jenkins集成
一、编译环境准备编译平台阿里云 Ubuntu20.04.5LTS安装编译环境依赖sudoapt-get-yinstallbuild-essentialasciidocbinutilsbzip2gawkgettextgitlibncurses5-devlibz-devpatchpython3python2.7unzipzlib1g-devlib32gcc1libc6-dev-i386subversionflexuglifyjsgit-coregcc-multilibp7zipp7zip-fullmsmtplibssl-devtexinfolibglib2.0-devxmltoqemu-utils
准备工作 从官网(OpenWrtFirmwareSelector)下载下图标注的两个文件 由于OpenWrt官网发布的固件会改写MTD分区布局,不支持原厂和OpenWrt共存,需要先刷入openwrt-ipq807x-generic-xiaomi_ax9000-initramfs-factory.ubi核心系统自动进行分区调整。进入AX9000SSH 进入方法请参考https://www.right.com.cn/forum/thread-5695827-1-1.html 通过执行下面这条命令记下当前原厂固件所在分区 nvramgetflag_b
让我们使用以下代码(conftest.py):importrandomdeftest_val():value=random.random()assertvalue运行py.test--junitxml=result.xmlconftest.py生成result.xml(当测试通过时):现在。我希望能够做的是将test_val()生成的值存储在results.xml中。有办法吗?我似乎无法在pytestdoc中找到任何相关内容. 最佳答案 附带的junitxml插件没有添加此类数据的Hook不过,您可以将它打印到标准输出,因为它已添加
一、简介Pytest是一个全功能Python测试工具,支持第三方扩展插件,能够使用其开展单元测试和复杂功能测试。可以和selenium、requests、appium等模块结合使用实现WEBUI、API、APP自动化测试。详见参考指南文档:https://docs.pytest.org/en/7.1.x/#PDF文档:https://media.readthedocs.org/pdf/pytest/latest/pytest.pdf二、安装0、前提:已安装配置好Python3.7+环境1、安装:在命令行或Pycharm终端中运行命令pipinstallpytest2、验证:运行命令pytest
如何使用bcdedit添加新的UEFI固件启动菜单条目(在NVRAM中)。例如我尝试了以下步骤,但未添加启动项。bcdedit/create/d"LinuxLoader"/applicationosloader这将返回一个新的guid(比如newguid)bcdedit/set{newguid}devicepartition=S:bcdedit/set{newguid}path\boot\efi\bootx64.efibcdedit/set{fwbootmgr}displayorder{newguid}/addfirst提前致谢。 最佳答案
pytestpytest是python的一种单元测试框架,同自带的unittest测试框架类似,但pytest更简洁高效。单元测试:测试函数、类、方法能不能正常运行测试的结果是否符合我们的预期结果安装pipinstall-Upytest基本使用通过pytest包使用importpytestdeftest_a():print("test_a")return1+0deftest_b():print("test_b")return1/0if__name__=='__main__':pytest.main()默认情况下:在main中直接使用pytest的main()方法,会把文件中所有test_*开头
前言用过pytest的小伙伴应该都知道,pytest之所以功能强大,是因为pytest的插件非常的多。这是插件大多是pytest的使用者所开发的,今天咱们专门来聊聊如何去自己开发Pytest的插件。一pytest插件的介绍pytest框架采用的是插件系统的模式来设计的,pytest运行的所有流程都是基于插件实现的钩子来实现的。一个插件包含一个或多个钩子函数。编写钩子解释了如何自己编写钩子函数的基础知识和细节。pytest通过调用插件的指定钩子来实现配置、收集、运行和报告的各个方面:内置插件:从pytest的内部_pytest目录加载。外部插件:通过setuptools入口点发现的模块conft
基于Windows下离线安装当前最新ArduinoESP32SDK(2.0.7)固件开发包✨写这篇的文章的初衷,是由于在前几天想通过离线一键安装包方式实现升级安装,结果发现解压后,可以找到开发板,但是无法上传代码,由于原作者在封装安装包的时候,将有效资源放的是其他平台上使用的,导致工程可以编译,但是上传会报错,特此加以补充安装方法。📜在使用https://arduino.me/packages/esp32.json离线安装包,编译-上传报错内容:java.io.IOException:Cannotrunprogram"REMOVE/esptool.exe":CreateProcesserror
编辑@Mike指出我下面代码中的try_lock函数是不安全的,并且访问器创建也会产生竞争条件。(来自每个人的)建议使我确信我走上了错误的道路。原始问题嵌入式微Controller上的锁定要求与多线程不同,我无法将多线程示例转换为我的嵌入式应用程序。通常我没有任何类型的操作系统或线程,只有main以及硬件定期调用的任何中断函数。我需要从中断中填充缓冲区是很常见的,但在main中处理它是很常见的。.我创建了IrqMutex下面的类来尝试安全地实现这一点。每个试图访问缓冲区的人都通过IrqMutexAccessor被分配了一个唯一的ID。,那么他们每个人都可以try_lock()和unlo