标签化管理
标签说明
根据现有业务需要,用例需要添加的标签有:
- 脚本 ID :自动化用例脚本/函数 ID
- *PMS用例ID :
PMS
上对应的用例 ID(用例库 ID) - 用例级别 :对应
PMS
上用例级别,分别用L1、L2、L3、L4
表示 - 用例类型 :
FUNC
(功能)、PERF
(性能)、STR
(压力)、SEC
(安全)、CTS
(兼容性)、API
(接口)、BASELINE
(基线-预留) - *设备类型 :
PPL
(依赖外设的用例)、COL
(依赖主控机的用例) - 一二级bug自动化 :
BUG
(由Bug
转的用例) - *上线对象 :
CICD
,表示上线到CICD
流水线的用例 - 跳过原因 :
skip-XXX
,用于控制用例是否执行 - 确认修复 :
fixed-XXX
,用于标记用例的修复状态 - 废弃用例 :
removed-已废弃
,用于标记已经废弃的用例,此用例标签不会被添加,也不会被执行
示例:
脚本ID | *PMS用例ID | 用例级别 | 用例类型 | *设备类型 | 一二级bug自动化 | *上线对象 | 跳过原因 | 确认修复 | 废弃用例 | ... |
---|---|---|---|---|---|---|---|---|---|---|
679537 | 679537 | L1 | FUNC | PPL | BUG | CICD | skip-XXX | fixed-XXX | removed-已废弃 | ... |
操作步骤
在子项目目录下新建
csv
文件,用于保存用例标签,以 用例脚本的 py 文件去掉首字符串 "test_" ,去掉用例序号后的字符串,取中间的名称作为 csv 文件的文件名 。例如: 相册的用例文件为
test_album_xxx.py
,xxx 表示用例的ID(也可以是自定义的数字代表用例序号),此时csv
文件名就应为album.csv
;对于用例规模比较大的应用,比如文件管理器,建议分模块,每个模块建立一个
csv
文件,所有csv
文件建议放在一个tags
目录下。是否分模块维护
csv
取决于应用的用例复杂度,同时我们应该充分考虑后期的可维护性,csv
文件太多了也是一个很糟糕的事情。第一列为脚本 ID,从第二列开始及之后的列,每一列都是一个用例标签;后续需要新增用例标签,可以直接在
csv
文件里面添加对应的列即可;用例标签可以无序。
跳过用例
传统跳过用例的方式是在用例脚本里面给用例添加装饰器(@pytest.mark.skip
),解除跳过时将装饰器代码删掉,这种方式需要修改用例代码,而通过 csv
文件来管理跳过用例则会方便很多;
将跳过用例操作也整合进入用例标签,在 csv
文件中新增一列为“跳过原因”;
1. 固定跳过
示例:
脚本ID | ...(各种用例标签) | 跳过原因 |
---|---|---|
679537 | ... | skip-受到某新需求影响 |
- 如果应用受到新需求影响需要跳过,则在此列备注具体的跳过原因。跳过的原因统一标签开头为 “
skip-XXX
”; - 用例执行时判断
csv
文件里面跳过原因列是否存在跳过标签,存在跳过标签则用例也不会被执行,最终的用例状态会被标签为SKIPED
。
2. 条件判断跳过
示例:
脚本ID | ...(各种用例标签) | 跳过原因 |
---|---|---|
001 | ... | skipif_platform-aarch64&mips64 |
- 某些用例会因为不同的环境判断用例是否执行,常见的场景为在不同架构上判断是否执行,跳过的原因标签为 “
skipif_platform-
” 加架构名,多个架构之间使用 “&
” 拼接; - 以上例子为用例执行时,判断当前架构是否为
arrch64
或者mips64
,若是,则跳过用例不执行,若否则执行用例;
在项目目录路径下存在文件 setting/skipif.py
,所有条件判断跳过的函数写在此文件中。
#!/usr/bin/env python3
# _*_ coding:utf-8 _*_
# SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
# SPDX-License-Identifier: GPL-2.0-only
"""
此配置文件用于标签化管理方案实现条件判断跳过的配置项;
在CSV文件中“跳过原因”列填入函数名和参数,即可实现条件判断跳过;
比如:
在CSV文件中“跳过原因”列填入:
skipif_platform-aarch64
函数名称为:skipif_platform,比如是此文件中定义了的函数;
参数为:aarch64,多个参数用 & 符号连接;
函数名与参数之间用 - (中横线)连接;
"""
import os
from setting.globalconfig import GlobalConfig
def skipif_platform(args: str):
"""平台跳过
skipif_platform-aarch64
"""
_skip_key = args.split("&")
for key in _skip_key:
if GlobalConfig.SYS_ARCH == key:
return True
return False
def skipif_not_platform(args: str):
"""平台不跳过
skipif_not_platform-aarch64
"""
return not skipif_platform(args)
def skipif_xdg_type(args: str):
"""skipif wayland or x11
skipif_xdg_type-wayland
"""
_skip_key = args.split("&")
for key in _skip_key:
if GlobalConfig.DISPLAY_SERVER == key:
return True
return False
def skipif_cpu_name(args: str):
"""skipif cpu name
使用 sudo dmidecode -s system-product-name 查看机器的cpu型号
剔除中横线和&符号,比如:KLVV-W5821,标签记录为 KLVVW5821
skipif_cpu_name-KLVVW5821
"""
_skip_key = args.split("&")
for key in _skip_key:
if (
os.popen(
f"echo '{GlobalConfig.PASSWORD}'| "
"sudo -S dmidecode -s system-product-name | awk '{print $NF}'"
)
.read()
.split("\n")[0]
.replace("-", "")
.replace("&", "")
== key
):
return True
return False
def skipif_not_cpu_name(args: str):
"""skipif not cpu name
使用 sudo dmidecode -s system-product-name 查看机器的cpu型号
剔除中横线和&符号,比如:KLVV-W5821,标签记录为 KLVVW5821
skipif_not_cpu_name-KLVVW5821
"""
return not skipif_cpu_name(args)
def skipif_os_version(args: str):
"""
系统版本跳过
skipif_os_version-1060
"""
_skip_key = args.split("&")
for key in _skip_key:
if key == GlobalConfig.version_cfg.get("MinorVersion"):
return True
return False
def skipif_not_os_version(args: str):
"""
系统版本不跳过
skipif_not_os_version-1060
"""
return not skipif_os_version(args)
if __name__ == '__main__':
a = os.popen(
f"echo '{GlobalConfig.PASSWORD}'| "
"sudo -S dmidecode -s system-product-name | awk '{print $NF}'"
).read().split("\n")[0]
print(a)
方法编写规范:
- 方法名必须以
skipif
开头; - 方法必须有返回结果并且为布尔值(
True
代表跳过,False
代表不跳过); - 方法只能有一个入参;
在 csv
文件跳过原因一栏中填写为 “{函数名}-{参数}
”,例如:skipif_platform-aarch64
;在用例收集阶段会以第一个 “-
” 进行分割,截取的左侧字符串作为函数名,在 skipif.py
文件中查找是否有同名函数,并将截取的右侧作为参数传递给该函数,通过获取该函数返回的布尔值,返回 True
,则用例不执行,返回 False
,则执行该用例。
重要
若函数需要多个参数,可自定义多个参数之间的连接符,连接符号不可使用下划线和逗号,推荐统一使用
&
符号;若需要多个 skipif 条件判断组合,使用
&&
符号将两个方法分开,比如:skipif_platform-aarch64&&skipif_xdg_type-wayland
;
确认修复
针对于某些用例修复后,但不能立即删除跳过原因(skip-XXX
)的用例,新增一列标签名为 “确认修复
”,作为标记该用例是否已经修复,固定填入字段为 “fixed-已修复
”。这样这条用例即使同时标记了 skip-XXX
也会正常执行。
示例:
用例ID | ...(各种用例标签) | 跳过原因 | 确认修复 |
---|---|---|---|
679537 | ... | skip-受到某新需求影响 | fixed-已修复 |
【同时标记了skip
和 fixed
,但仍然想要跳过用例】
当 “跳过原因” 和 “确认修复” 中同时填入后,命令行传递参数 --ifixed yes
,则代码不会执行该条用例。
python3 manage.py run --ifixed yes
看到这里有些同学可能要问了,我想恢复跳过执行,直接把 skip-XXX
这一列标签删掉不就好了,还搞什么确认修复干啥?
这里给各位看官稍微解释一下:
(以下流水线指的是每日构建的流水线,跑 AT 的全量用例)
首先,流水线上跑的是 AT 历史 Tag,跳过用例的标签(skip-XXX
) 是在最新的代码上提交的,我们采用最新的 csv
文件覆盖历史 csv
文件的设计来实现了对历史 Tag 上用例的跳过;
然后,在日常跳过用例的过程中,同时也在修复一些用例,修复后的这些用例在本地调试的时候我们不希望继续跳过,但是此时,修复的这些用例可能还不稳定,不适合马上放到流水线去跑,也就是说流水线上我们是希望他继续跳过的,因此,咱不能直接把 skip-XXX
干掉;
这里就矛盾了,一个需求是想修复了立马解除跳过,另一个需求又不想修复了立马解除跳过,怎么办呢?
我们使用“确认修复”来标记这条用例已经修复了,这样你本地调试用例的时候这条已修复的用例是会执行的,同时在流水线上将 --ifixed yes
参数加上,那么流水线上执行时这条用例仍然是跳过的状态,后续你打 Tag 的时候,把 “跳过原因” 和 “确认修复” 中的标签全部删掉就可以了。
这就是“确认修复”这个标签的背景,需要各位看官稍微品一品。
废弃用例
针对某些用例,由于需求变更,环境影响或评估不再适用于自动化测试时,用例需要废弃,则新增一列标签名为 “废弃用例”,该列存在 “removed-{废弃原因}”,则用例不会执行。
用例ID | ...(各种用例标签) | 跳过原因 | 确认修复 | 废弃用例 |
---|---|---|---|---|
679537 | ... | skip-受到某新需求影响 | fixed-已修复 | removed-已废弃 |
设计思路
上面介绍 Pytest
框架提供的标签功能 mark,使用时需要为每一个用例添加标签装饰器,则操作复杂,可维护性差,其根本问题就是标签分散在每一条用例的装饰器上,难以集中维护;于是乎将所有标签使用 csv
文件进行集中管理,并通过 Pytest
的钩子函数,读取 csv
文件,动态添加标签到用例中。
CSV文件格式
此配置文件需要维护大量的标签数据,且要方便能使用 Excel
打开进行编辑查看,更重要的是我们不想引入三方依赖,CSV
文件几乎是唯一能满足所有的要求的文件格式。