2.数据渲染与校验(data和scm) - Be5yond/pytest_demo GitHub Wiki
业务中经常要有接口B的请求参数依赖接口A的返回中的某个数据这种情况。即上下文的依赖。
需要自动化测试的数据支持变量,代码执行的时候动态替换,提高测试数据的可维护性
数据渲染
数据替换规则
1. 变量替换
- '{{}}' 测试数据中两个大括号扩起来的数据被认为是一个变量,如:{'DevToken': '{{ token }}' } 会替换成{'DevToken': '1164fd92ea0a3ab'}
有了变量替换的规则,那么变量的值从哪里来呢,两个来源
1.1 配置文件
不同环境的域名,账号,资源id,db地址等数据。如本demo中的config.ini文件中配置
[env_test]
host = http://httpbin.org
hippo: {
"user": "wululu",
"pwd": "pa55word"
}
cache: {
"user": "username",
"pwd": 111111,
"predefine_id": "20",
"argument": "beyond"
}
1.2 上下文数据
实际业务中必然会有的场景是A返回的某个值,作为接口B的请求参数这样的情况。
Req支持使用jmespath语法查询上一个请求返回的数据,讲目标数据放到缓存池中,供后续的请求替换。
jmespath是一个json数据查询语法,如目标数据为:
{"a": {
"b": {
"c": [
{"d": [0, ["target", 2]]},
{"d": [3, 4]}
]
}
}}
使用a.b.c[0].d[1][0]可取到数据中的target, jmespath功能非常强大,详细教程参考jmespath官网
本例中Req提供statsh方法,将数据缓存赋值给变量。
user.commit_order(data[0])
# 将返回中json数据'json.type'下的值赋值给order_id
user.stash('json.type', 'order_id')
# 后续请求中的'{{ order_id }}' 将被替换成这里缓存的值
2. 函数替换
- '{%%}' 测试数据中大括号加%括起来的数据被认为是一个函数,执行的时候会替换成函数执行结果,如:{'st_id': '{% random.randint(1, 10) %}'} 会替换成{'st_id': 5}
2.1 数据构造函数
默认引用了faker来生成一些动态的假数据
2.2 自定义替换函数
除了内置的函数和faker提供的功能,特定业务需要自定义的数据生成函数。
可以自定义函数然后放到/comm/tools.py文件中,示例代码如下:
def randstr(l):
"""
:param l: string length
:return: a string object
"""
return ''.join((random.choice(string.ascii_letters) for i in range(l)))
def timestr(**kwargs):
"""
generate "2017-03-07T00:00+0800" format time string
:param kwargs: shifting parameters e.g. hours=3 days=-1
:return:
"""
now = arrow.now(tz='Asia/Shanghai')
t = now.shift(**kwargs)
return t.format('YYYY-MM-DDTHH:mm+0800')
一个完整的测试数据实例,数据:
{ 'key': {
'company': '{% fake.company() %}',
'phone': '{% fake.phone_number() %}',
'timestr': '{% timestr(hours=1) %}'
},
'foo': [
'{{ val }}',
{'newkey': '{{ val }}'}
]
}
运行时会动态替换成
{ 'key': {
'company': ' 凌颖信息传媒有限公司',
'phone': '13481047148',
'timestr': '2020-08-26T17:41+0800'
},
'foo': [
456,
{'newkey': 456}
]
}
数据校验
一条完整的case必要包含输入数据和预期结果,实现数据与测试代码分离,预期结果的校验也不能再代码中编写assert语句。
将预期结果的校验方法和测试输入数据成对放到一起管理,可以有两种方式来表达数据校验的规则
1.对json结果,采用jasonschema的方式进行校验,本项目采用schema,复杂的校验规则查看该项目文档
2.对于其他返回的结果,如xml格式,先转成json在用schema进行校验 😄
为什么选用schema而不是jsonschema?
答案是😀一致性和😀易用性
举个例子,如果我需要对如下数据进行校验
data = { 'type': 2 }
# 使用schema
Schema({'type': int}).validate(data)
# 使用jsonschema
schema = {
"type" : "object",
"properties" : {
"type" : {"type" : "number"}
},
}
validate(instance=data, schema=schema)
同样是校验数据类型是不是int,jsonschema的模板破坏了原有的数据结构,而schema的模板可以和校验数据保持一致。
另外,对于更加复杂的校验逻辑,使用jsonschema模板规则描述会更加复杂的多,而利用schema的灵活性,使用python 函数来校验,减少了jasonschema语法的学习的成本。校验函数也支持自定义函数,减少模板的编写难度。也为校验增加了😀灵活性。
一个复杂的校验
如:需要对前面渲染出来的结果进行校验
{ 'key': {
'company': ' 凌颖信息传媒有限公司',
'phone': '13481047148',
'timestr': '2020-08-26T17:41+0800'
},
'foo': [
456,
{'newkey': 456}
]
}
对应的的schema为
{ 'key': {
'company': str, # key.company 返回是一个字符串
'phone': is_valid_phone # 调用is_valid_phone对key.phone字段进行校验,自定义函数同样写在 /comm/tools.py中
}, # 模板中没有的字段,对timestr不进行校验
'foo': [
456, # 校验foo[0] == 456
{'newkey': 456} # 校验foo.newkey == 456
]
}
数据存储
因为schema的校验模板不是json数据(包含了python数据类型,函数等),存储的时候也是需要做一些规则转换,转换规则同数据的渲染一致。
schema模板数据存储为
{'key': {
'company': '{% str %}', # 函数
'phone': '{% is_valid_phone %}' # 自定义函数
},
'foo': [
'{{ val }}', # 变量
{'newkey': '{{ val }}'} # 变量
]
}