Antelope(羚羊) 自动化测试框架是一个基于pytest
的自动化测试框架。使用者可以在这个框架下使用 python 的原生测试用例和本框架支持的yaml
格式的自动化测试脚本,以便于团队中处于不同编码阶段的测试人员,都能共同构筑自动化测试。框架目前还是一个原始的阶段,受限于使用人数,它可能还是一个刚刚会走的婴儿,希望这篇文章可以抛砖引玉,收到社区的意见,做进一步的改进设置是共同构建。
框架设计之初,主要是为了解决接口自动化的具体问题,所以yaml
用例中有一些包含api
、request
字眼的关键字,后续我们会着手于 UI 自动化,丰富我们的内置步骤。
开发环境默认都是在MacOS
和vscode
上进行,对于Pycharm
和Windows
的适配都十分有限,所以一些快捷工具可能会失效,但是不会影响我们正常使用框架。
1、请先拉取仓库
2、按照仓库内 readme 的操作,并初始化我们的环境。
3、安装 allure 测试报告框架
4、运行python3 regression_test.py
,确保我们的环境安装正确
下面有这样的目录结构及文件内容
demo_case
- v2
- hello_world
- hello_world_template.yaml
- hello_world_value.yaml
- hello_world.py
runner.py
hello_world_template.yaml 内容如下
_version: 2.0
case:
title: "hello world"
test_step:
- set_by_json: { "a": 2, "b": 3 }
- assertEqual:
first: ${a}
second: ${b}
msg: a != b,用例执行失败
hello_world.py 内容如下
import allure
@allure.title('含操作符')
def test_a_and_b():
with allure.step('a = 1+1 , b = 2'):
a , b = 1+1 , 2
assert a == b , 'a != b,用例执行失败'
@allure.title('不含操作符')
def test_a_and_b_2():
with allure.step('a = 1 , b = 2'):
a , b = 1 , 2
assert a == b , 'a != b,用例执行失败'
执行下面命令行,执行用例
python3 runner.py demo_case/v2
allure 报告如下
# 使用文件夹
python runner.py dirname
# 指定某个文件
python runner.py yaml_file
# 指定python文件
python runner.py py_file
1、在开始执行前,程序会开始遍历指定目录下所有 xxx_template.yaml 文件,和所有 python 文件或是某个文件
2、xxx_template.yaml 会查找 xxx_value.yaml 文件作为自己的局部变量,找不到的情况下会生成一个空的全局变量
3、用例转换为一个个可执行步骤,然后执行。
用例的形式BDD
(Behavior Driven Development) 的step by step
风格,用例编写起来会更加简单。一个文件中会有多个用例且用例都以 case 为开头 。test_step 是一个必填数组,里面供我们放入步骤去执行。内置基础步骤有变量设置、断言、数据查询、接口请求等,步骤有很多,详见步骤列表。
_version: 2.0
# 第一个用例
case:
test_step:
# 多个步骤
- set_by_json: { "a": 2, "b": 3 }
- assertEqual:
first: ${a}
second: ${b}
msg: a != b,用例执行失败
# 第二个用例
case2: ...
下面是用例的可选参数
字段 | 使用 |
---|---|
level | 用例优先级,默认为 DEF_LEVEL |
is_skip | 是否跳过默认为 False |
skip_reason | 跳过是展示原因 |
remark | 备注,用于 allure 的 description |
module_path | 模块,用于 allure 的 story 和 tag |
title | allure 的用例标题 |
exec_env | str 或者是 list,指定用例可执行的环境 |
辅助用户使用不同的组合去执行用例,使用则执行指定 suite 文件的用例,减少回归用例时间。当同时指定 case_file 和 suite,会优先使用 suite。
antlope 中参数化的方式为${xxx}
(旧有 v1 用例支持{xxx}
,但是已经废弃不在支持),我们在执行的过程中变量都可以通过这个方式引用,同时也支持jsonpath
去引用。在单独使用参数化,参数最终会转化为实际值,如果参数在字符串内的情况下,参数始终以str(xxx)
的形式出现。c3 的引用就是如此。
_version: 2.0
# 第一个用例
case:
test_step:
- set_by_json:
{ "a": 2, "b": 3, "c": { "c1": 1, "c2": [4, 2], "c3": null },"d":[1,32,"456"] }
- echo: "${a}"
- echo: "${c}.c1"
- echo: "${c}.c2.0"
- echo: " ${c}.c2.0 == ${c}.c2.1 "
- echo: "${c}.c3 is None"
全局变量从GLOBAL_VALUE_FILENAME
中读取,他是是方便我们定义通用的变量,它本身也是yaml
文件,使用根节点来作为环境,我们使用-e
去运行,在不指定环境的情况下默认返回{}
。全局变量不同于局部变量,一些数据链接、oss 链接都会在初始全部变量时生成,这一内容在自定义数据链接详细说明
global_value.yaml 如下
demo: { "admin_phone": "135" }
dev: {
"admin_phone": "189"
db:
mysql:
host: "127.0.0.1"
port: 3306
username: "root"
pwd: a123456
dbname: "dev"
type: mysql
}
demo_template.yaml
case:
test_step:
- echo: "${admin_phone}"
指定环境执行
python3 demo_template.yaml -e demo
python3 demo_template.yaml -e dev
用例变量和全部变量相似,使用根节点来作为环境,同时需要一个二级节点和 use_value 配合使用,用例变量和全局变量组合成全局变量 (用例变量>全局变量),在没有找到时则使用全局变量生成局部变量。
demo_template.yaml
case:
use_value: 400phone
title: 400电话
test_step:
- echo: "${admin_phone}"
case2:
title: 个人电话
test_step:
- echo: "${admin_phone}"
demo_value.yaml
demo: {
"400phone": {"admin_phone": "400-99999" }
}
用例中步骤是重要组成部分,无论我们的前置步骤、后置步骤、断言都是步骤。步骤的形式十分简单,仍是 json 的的基础类型,形式如下:
步骤1: 1.0
步骤2: ''
步骤3:
参数1: 'aaa'
参数2: 'aaa'
步骤4:
- a
- b
参数的形式是断言自己决定的,并不是恒定不变的大部分断言步骤都是支持数组和对象入参
class AssertStep(metaclass=ABCMeta):
"""各类断言步骤(基本可以照抄unittest)"""
def __init__(self, paramers, *args, **kwargs):
self.unzip_paramers(paramers)
...
def unzip_paramers(self, paramers):
if isinstance(paramers, list):
self.set_args(paramers)
elif isinstance(paramers, dict):
self.set_kwargs(paramers)
def set_kwargs(self, paramers: dict):
for k, v in paramers.items():
setattr(self, k, v)
@abstractmethod
def set_args(self, args: list):
pass
...
class AssertEqualStep(AssertStep):
"""断言str(first)和str(second)相等"""
def set_args(self, args):
self.first, self.second, self.msg, *_ = args
self.first, self.second = str(self.first), str(self.second)
def execute(self):
assert self.first == self.second, self.msg
@classmethod
def snippet(self):
return """
- assertEqual:
first:
second:
msg:
""", self. __doc__
步骤允许这样的使用
case:
test_step:
# 步骤推荐写法
- assertEqual:
first: 1
second: 1
msg: "a != b"
# 步骤兼容写法
- assertEqual:
- 1
- 1
- "a != b"
- echo: after 1 sec, case end
- sleep: 1
在框架中断言不会中断用例执行,在执行的过程中如果遇到失败,框架会记录下断言的异常信息。
如果你希望严格执行可在modules/case_executor.py
的execute_step
注释掉run_with_assert
装饰器
@run_with_assert
def execute_step(self, step_class, step_args):
...