2.2.2 pytest装饰器
@pytest.fixture
:用于定义夹具(fixture),夹具是一种可以在测试用例中重复使用的资源或数据,例如数据库连接、临时文件、模拟对象等。
对固件驱动。1. 主要用于准备测试所需的数据、对象、环境等,并在测试结束后进行清理操作,以确保测试之间不会相互影响。2. 通过将常见的测试准备和清理逻辑封装到 fixture 中,您可以在多个测试用例中重复使用,从而避免重复编写相同的代码。3. fixture 可以用于管理外部资源,如数据库连接、文件句柄等,以确保资源在测试完成后被释放。 |
@pytest.mark.parametrize
:用于参数化测试,允许你通过多个参数组合运行同一个测试用例,以减少重复的测试代码。
对数据驱动:@pytest.mark.parametrize(参数名,参数值-列表或者元组),数据中有多少值就会执行多少次。用于在一个测试用例中多次运行,每次使用不同的参数,即使用不同的输入数据运行相同的测试逻辑 |
@pytest.mark.skip 和 @pytest.mark.skipif:用于跳过指定的测试用例,前者是无条件跳过,后者可以根据条件来决定是否跳过。
@pytest.mark.xfail:用于标记预期失败的测试用例,即使测试用例失败了,也不会导致整个测试过程失败。
@pytest.mark.parametrize:用于参数化测试,让你可以为测试用例指定多组参数,使得同一个测试用例可以多次运行。
@pytest.mark.timeout:用于为测试用例设置最大运行时间,如果测试用例运行时间超过指定时间,将会被中断。
@pytest.mark.parametrize:用于将标记应用于测试用例,例如自定义标记,用于组织测试用例。
@pytest.mark.usefixtures:用于在测试函数中自动使用指定的夹具,不需要在参数列表中指定。
@pytest.mark.filterwarnings:用于过滤特定类型的警告,以便在测试运行期间不显示特定的警告信息。
@pytest.mark.raises:用于断言某个异常被正确地引发,用于测试代码中是否抛出了预期的异常。
2.2.3 断言、allure测试报告
还需要安装allure,才能通过os模块调用,这里仅放一个基础使用例子,在该系列的后续文章**自动化测试(四)**中细讲。
2.2.4 接口关联、封装改进
接口关联场景:在测试中,一个系统通常会被分解成多个子系统或模块,这些子系统之间需要通过接口进行数据传递和交互。比如test1中验证了能够获得tokens,test2需要使用test1的tokens。
方法一:对于流水线测试,中间数据传输比较少的话,可以在 pytest 的 fixture 中使用 yield 语句来在 fixture 的生命周期内传递参数,并确保 yield 生成的数据被另外一个测试用例以函数名称传输的方式捕获。
方法二:用文件、数据库保存,常用yaml文件。用文件或者数据库统一管理中间变量。
common\yaml_uitl.py文件
# 提前构建一个yaml文件
import yaml
import os
def read_yaml(key):
# 使用 with 会自动管理文件的打开和关闭
with open(os.getcwd() + "/extract.yaml", encoding="utf-8") as f:
value = yaml.load(stream=f, Loader=yaml.FullLoader) # 自动将yaml结构体
print(value)
return value[key]
def write_yaml(data):
# 理论上还需要检测yaml中是否已经存在对应的数据,如果存在需要改mode
with open(os.getcwd() + "/extract.yaml", encoding="utf-8", mode='a') as f:
yaml.dump(data, stream=f, allow_unicode=True)
if __name__ == "__main__":
print(read_yaml("employee"))
write_yaml({"employer": {"name": "Jerry"}})
print(read_yaml("employer"))
一般在conftest文件中设置clear_yaml函数。接口关联时使用yaml_util直接写入、读取json数据即可。
YAML 文件人类易读性比Json好,可以和json之间灵活转换(load后就是json格式)
|
# 特殊字符可以使用单引号或双引号括起来
employee:
name: Mark
age: 28
status: null # 空值可以表示为 null 或 ~
projects:
- Project A # - 表示列表中的元素
- Project B
contact: # 联系方式
email: mark@example.com
phone: 123-456-7890
description: | # | 表示多行字符串
This is a multiline
string with preserved line breaks.employer:
employer:
name: Jerry
YAML动态传参(热加载)
热加载:让YAML能够调用外部函数
方法:${fuction_name(parms)}
2.3 pytest接口封装(统一请求封装)
将数量很多的用例封装为一个方法。场景:
- 统计数据
- 异常处理
- 日志监控
eg1:以处理数据为例,将待翻译的内容封装成GoogleTranslate.py中的google_translator类。
eg2:以日志监控为例,封装后在SendRequest类方法中打印日志即可,因为所有的用例中都会调用SendRequest类方法。同时自建的类只初始化一次session对象(能够自动关联cookie,所有请求都在一个通话里面),而google_translator类with requests.Session() as s,或者request方法源码也是先from . import sessions然后with sessions.Session() as session,cookie都只用了一次
为什么可以requests.Session(),而不需要requests.sessions.Session()? requests 库在设计时采用了适当的模块导入机制和命名空间。这样的设计使得库的使用更加便捷和一致。当你使用 import requests 导入 requests 模块时,你实际上导入了 requests 包中的 init.py 模块。然后,requests 包内的各个子模块和类都会在 requests 命名空间下变得可用。 |