PyTest测试框架学习日记
我们先了解一下软件的测试,软件测试一般分为如下四个方面
- 单元测试:称模块测试,针对软件设计中的最小单位——程序模块,进行正确性检查的测试工作
- 集成测试:称组装测试,通常在单元测试的基础上,将所有程序模块进行有序的、递增测试,重点测试不同模块的接口部分
- 系统测试:将整个软件系统看成一个整体进行测试,包括对功能、性能以及软件所运行的软硬件环境进行测试
- 验收测试:指按照项目任务书或合同、供需双方约定的验收依据文档进行的对整个系统的测试与评审,决定是否接收或拒收系统
pytest最初是作为一个单元测试框架而设计的,但它也提供了许多功能,使其能够进行更广泛的测试,包括集成测试,系统测试,他是一个非常成熟的全功能的python 测试框架。 它通过收集测试函数和模块,并提供丰富的断言库来简化测试的编写和运行,是一个非常成熟且功能强大的 Python 测试框架,具有以下几个特点:
- 简单灵活:Pytest 容易上手,且具有灵活性。
- 支持参数化:您可以轻松地为测试用例提供不同的参数。
- 全功能:Pytest 不仅支持简单的单元测试,还可以处理复杂的功能测试。您甚至可以使用它来进行自动化测试,如 Selenium 或 Appium 测试,以及接口自动化测试(结合 Pytest 和 Requests 库)。
- 丰富的插件生态:Pytest 有许多第三方插件,您还可以自定义扩展。一些常用的插件包括:
pytest-selenium
:集成 Selenium。pytest-html
:生成HTML测试报告。pytest-rerunfailures
:在失败的情况下重复执行测试用例。pytest-xdist
:支持多 CPU 分发。
- 与 Jenkins 集成良好。
- 支持 Allure 报告框架。
本文将基于测试需求简单介绍pytest的用法。
Pytest安装
# 安装pytest:
pip install pytest
# 升级pytest
pip install -U pytest
# 查看pytest版本
pytest --version
# 查看已安装包列表
pip list
# 查看pytest帮助文档
pytest -h
# 安装第三方插件
pip install pytest-sugar
pip install pytest-rerunfailures
pip install pytest-xdist
pip install pytest-assume
pip install pytest-html
Pytest使用
命名规则
# 首先在使用pytest 时我们的模块名通常是以test开头或者test结尾,也可以修改配置文件,自定义命名规则
# test_*.py 或 *_test.py
test_demo1
demo2_test# 模块中的类名要以Test 开始且不能有init 方法
class TestDemo1:
class TestLogin:# 类中定义的测试方法名要以test_开头
test_demo1(self)
test_demo2(self)# 测试用例
class test_one:def test_demo1(self):print("测试用例1")def test_demo2(self):print("测试用例2")
Pytest 参数
pytest支持很多参数,可以通过help命令查看
pytest -help
我们在这里列出来常用的几个:
-m: 用表达式指定多个标记名。 pytest 提供了一个装饰器 @pytest.mark.xxx,用于标记测试并分组(xxx是你定义的分组名),以便你快速选中并运行,各个分组直接用 and、or 来分割。
-v: 运行时输出更详细的用例执行信息 不使用-v参数,运行时不会显示运行的具体测试用例名称;使用-v参数,会在 console 里打印出具体哪条测试用例被运行。
-q: 类似 unittest 里的 verbosity,用来简化运行输出信息。 使用 -q 运行测试用例,仅仅显示很简单的运行信息, 例如:
.s.. [100%]
3 passed, 1 skipped in 9.60s
-k: 可以通过表达式运行指定的测试用例。 它是一种模糊匹配,用 and 或 or 区分各个关键字,匹配范围有文件名、类名、函数名。
-x: 出现一条测试用例失败就退出测试。 在调试时,这个功能非常有用。当出现测试失败时,停止运行后续的测试。
-s: 显示print内容 在运行测试脚本时,为了调试或打印一些内容,我们会在代码中加一些print内容,但是在运行pytest时,这些内容不会显示出来。如果带上-s,就可以显示了。
pytest test_se.py -s
Pytest 选择测试用例执行
在 Pytest 中,您可以按照测试文件夹、测试文件、测试类和测试方法的不同维度来选择执行测试用例。
- 按照测试文件夹执行
# 执行所有当前文件夹及子文件夹下的所有测试用例
pytest .
# 执行跟当前文件夹同级的tests文件夹及子文件夹下的所有测试用例
pytest ../tests# 按照测试文件执行
# 运行test_se.py下的所有的测试用例
pytest test_se.py# 按照测试类执行,必须以如下格式:
pytest 文件名 .py:: 测试类,其中“::”是分隔符,用于分割测试module和测试类。
# 运行test_se.py文件下的,类名是TestSE下的所有测试用例
pytest test_se.py::TestSE# 测试方法执行,必须以如下格式:
pytest 文件名 .py:: 测试类 :: 测试方法,其中 “::” 是分隔符,用于分割测试module、测试类,以及测试方法。
# 运行test_se.py文件下的,类名是TestSE下的,名字为test_get_new_message的测试用例
pytest test_se.py::TestSE::test_get_new_message# 以上选择测试用例的方法均是在**命令行**,如果您想直接在测试程序里执行可以直接在main函数中**调用pytest.main()**,其格式为:
pytest.main([模块.py::类::方法])
此外,Pytest 还支持控制测试用例执行的多种方式,例如过滤执行、多进程运行、重试运行等。
使用Pytest编写验证
- 在测试过程中,我们使用之前验证过的加法器,进入Adder文件夹,在picker_out_adder目录下新建一个test_adder.py文件,内容如下:
# 导入测试模块和所需的库
from UT_Adder import *
import pytest
import ctypes
import random# 使用 pytest fixture 来初始化和清理资源
@pytest.fixture
def adder():# 创建 DUTAdder 实例,加载动态链接库dut = DUTAdder()# 执行一次时钟步进,准备 DUTdut.Step(1)# yield 语句之后的代码会在测试结束后执行,用于清理资源yield dut# 清理DUT资源,并生成测试覆盖率报告和波形dut.Finish()class TestFullAdder:# 将 full_adder 定义为静态方法,因为它不依赖于类实例@staticmethoddef full_adder(a, b, cin):cin = cin & 0b1Sum = ctypes.c_uint64(a).valueSum += ctypes.c_uint64(b).value + cinCout = (Sum >> 64) & 0b1Sum &= 0xffffffffffffffffreturn Sum, Cout# 使用 pytest.mark.usefixtures 装饰器指定使用的 fixture@pytest.mark.usefixtures("adder")# 定义测试方法,adder 参数由 pytest 通过 fixture 注入def test_adder(self, adder):# 进行多次随机测试for _ in range(114514):# 随机生成 64 位的 a 和 b,以及 1 位的进位 cina = random.getrandbits(64)b = random.getrandbits(64)cin = random.getrandbits(1)# 设置 DUT 的输入adder.a.value = aadder.b.value = badder.cin.value = cin# 执行一次时钟步进adder.Step(1)# 使用静态方法计算预期结果sum, cout = self.full_adder(a, b, cin)# 断言 DUT 的输出与预期结果相同assert sum == adder.sum.valueassert cout == adder.cout.valueif __name__ == "__main__":pytest.main(['-v', 'test_adder.py::TestFullAdder'])
- 运行测试之后输出如下:
collected 1 itemtest_adder.py ✓ 100% ██████████Results (4.33s):
测试成功表明,在经过114514次循环之后,我们的设备暂时没有发现bug。然而,使用多次循环的随机数生成测试用例会消耗大量资源,并且这些随机生成的测试用例可能无法有效覆盖所有边界条件。在下一部分,我们将介绍一种更有效的测试用例生成方法。
Pytest 使用手册 — learning-pytest 1.0 文档https://learning-pytest.readthedocs.io/zh/latest/