介面自動化全量欄位校驗
介面自動化全量欄位校驗
更新 2.0.1 版本:
- 新增 json 格式契約校驗
- 新增根據響應結果自動生成 json 契約方法
github 地址:https://github.com/xglh/PactVerify_demo
與 httprunner(2.5.7) 結合 demo:https://github.com/xglh/httprunner-pactverify-demo
目錄:
- 一.背景
- 二.校驗原則
- 三.快速使用
- 1、python 類契約使用
- 2、json 契約使用
- 3、python 類契約轉 json 契約
- 4、根據響應結果自動生成 json 契約
- 1、python 類契約使用
- 四.基本匹配規則
- 1、Matcher 類,校驗規則:值匹配
- 2、Like 類,校驗規則:型別匹配
- 3、EachLike 類,校驗規則:陣列型別匹配
- 4、Term 類,校驗規則:正則匹配
- 5、Enum 類,校驗規則:列舉匹配
- 五.複雜資料結構匹配規則
- 1、{{}}格式
- 2、[[]] 格式
- 3、{[]}格式
- 4、Like-Term 巢狀
- 5、Like-Matcher 巢狀
- 六. 異常場景匹配
- 1、null 匹配
- 2、{}匹配
- 3、json 格式字串匹配
- 4、key 不存在匹配
- 5、多型別匹配
- 6、非強制欄位匹配
- 七.unittest+HTMLTestRunner+ 契約斷言示例
- 八.優點總結
一.背景
公司前端吐槽後臺介面有時會更改返回的資料結構,返回的欄位名與欄位型別與介面文件不一致,希望有一個快速檢測介面返回資料的所有欄位名與欄位型別的方法
以下方資料為例,要校驗 data 陣列中 dict 結構中的欄位名與欄位型別,可以寫指令碼遍歷資料,但是由於每個介面返回的資料結構可能不一致,可能需要針對每個介面做不同的邏輯,所以需要一個比較通用的校驗方法
{
"msg": "success",
"code": 0,
"data": [{
"type_id": 249,
"name": "王者榮耀",
"order_index": 1,
"status": 1,
"subtitle": " ",
"game_name": "王者榮耀"
}, {
"type_id": 250,
"name": "絕地求生",
"order_index": 2,
"status": 1,
"subtitle": " ",
"game_name": "絕地求生"
}, {
"type_id": 251,
"name": "刺激戰場",
"order_index": 3,
"status": 1,
"subtitle": " ",
"game_name": "刺激戰場"
}
]
}
在研究了契約測試後,抽取pact-python部分程式碼,實現:自定義介面返回資料格式 (【契約定義】)-實際響應資料格式校驗 (【契約校驗】) 的功能
備註:這裡的【契約】等同於介面響應資料結構
二.校驗原則
1.實際返回欄位名要嚴格等於或者含契約定義欄位名(根據不同匹配模式來確定)
2.欄位值可以值相等或型別相等
目標:對返回資料進行全量 (欄位名 - 值/型別) 校驗
契約定義方式:支援 python 類契約和 json 契約
三.快速使用
安裝:
pip install pactverify
1.python 類契約使用
from pactverify.matchers import Matcher, Like, EachLike, Enum, Term, PactVerify
# 定義契約格式
expect_format = Matcher({
'code': 0, # code key存在,值相等,code==0
'msg': 'success', # msg key存在,值相等,msg=='success'
# [{}]結構
'data': EachLike({
"type_id": 249, # type_id key存在,值型別相等,type(type_id) == type(249)
"name": "王者榮耀", # name key存在,值型別相等,type(name) == type("王者榮耀")
}),
'type': Enum([11,22]),
'list': EachLike(11,minimum=2)
})
# 實際返回資料
actual_data = {
"msg": "success",
"code": 1,
'type': 12,
"data": [{
# type_id型別不匹配
"type_id": '249',
"name": "王者榮耀"
}, {
# 缺少name
"type_id": 250,
}, {
# 比契約定義多index欄位
"type_id": 251,
"name": "刺激戰場",
"index": 111
}
],
'list': [11]
}
# hard_mode預設為true,hard_mode = True時,實際返回key必須嚴格等於預期key;hard_mode = False時,實際返回key包含預期key即可
mPactVerify = PactVerify(expect_format, hard_mode=True)
# 校驗實際返回資料
mPactVerify.verify(actual_data)
# 校驗結果 False
print(mPactVerify.verify_result)
''' 校驗錯誤資訊
錯誤資訊輸出actual_key路徑:root.data.0.name形式
root為根目錄,dict型別拼接key,list型別拼接陣列下標(從0開始)
{
# 實際key少於預期key錯誤
'key_less_than_expect_error': ['root.data.1.name'],
# 實際key多與預期key錯誤,只在hard_mode = True時才報該錯誤
'key_more_than_expect_error': ['root.data.2.index'],
# 值不匹配錯誤
'value_not_match_error': [{
'actual_key': 'root.code',
'actual_value': 1,
'expect_value': 0
}
],
# 型別不匹配錯誤
'type_not_match_error': [{
'actual_key': 'root.data.0.type_id',
'actual_vaule': '249',
'expect_type': 'int'
}
],
# 陣列長度不匹配錯誤
'list_len_not_match_error': [{
'actual_key': 'root.list',
'actual_len': 1,
'min_len': 2
}
],
# 列舉不匹配錯誤
'enum_not_match_error': [{
'actual_key': 'root.type',
'actual_value': 12,
'expect_enum': [11, 22]
}
]
}
'''
print(mPactVerify.verify_info)
2.json 契約使用
from pactverify.matchers import PactJsonVerify
# 定義json契約格式
expect_format = {
'$Matcher': {
'code': 0, # code key存在,值相等,code==0
'msg': 'success', # msg key存在,值相等,msg=='success'
# [{}]結構
'data': {
'$EachLike': {
"type_id": 249, # type_id key存在,值型別相等,type(type_id) == type(249)
"name": "王者榮耀", # name key存在,值型別相等,type(name) == type("王者榮耀")
}},
'type': {
'$Enum': [11, 22]
},
'list': {
'$EachLike': {
# $values,$params形式傳遞額外引數
'$values': 11,
'$params': {
'minimum': 2
}
}
}
}
}
# 實際返回資料
actual_data = {
"msg": "success",
"code": 1,
'type': 12,
"data": [{
# type_id型別不匹配
"type_id": '249',
"name": "王者榮耀"
}, {
# 缺少name
"type_id": 250,
}, {
# 比契約定義多index欄位
"type_id": 251,
"name": "刺激戰場",
"index": 111
}
],
'list': [11]
}
# hard_mode預設為true,hard_mode = True時,實際返回key必須嚴格等於預期key;hard_mode = False時,實際返回key包含預期key即可
# separator可自定義指定json關鍵字識別符號,預設為$
mPactJsonVerify = PactJsonVerify(expect_format, hard_mode=True, separator='$')
# 校驗實際返回資料
mPactJsonVerify.verify(actual_data)
# 校驗結果 False
print(mPactJsonVerify.verify_result)
''' 校驗錯誤資訊
錯誤資訊輸出actual_key路徑:root.data.0.name形式
root為根目錄,dict型別拼接key,list型別拼接陣列下標(從0開始)
{
# 實際key少於預期key錯誤
'key_less_than_expect_error': ['root.data.1.name'],
# 實際key多與預期key錯誤,只在hard_mode = True時才報該錯誤
'key_more_than_expect_error': ['root.data.2.index'],
# 值不匹配錯誤
'value_not_match_error': [{
'actual_key': 'root.code',
'actual_value': 1,
'expect_value': 0
}
],
# 型別不匹配錯誤
'type_not_match_error': [{
'actual_key': 'root.data.0.type_id',
'actual_vaule': '249',
'expect_type': 'int'
}
],
# 陣列長度不匹配錯誤
'list_len_not_match_error': [{
'actual_key': 'root.list',
'actual_len': 1,
'min_len': 2
}
],
# 元祖不匹配錯誤
'enum_not_match_error': [{
'actual_key': 'root.type',
'actual_value': 12,
'expect_enum': [11, 22]
}
]
}
'''
print(mPactJsonVerify.verify_info)
3.python 類契約轉 json 契約
1、python類契約不帶引數
# python類契約
expect_format = Like({'k1': 'v1'})
# json契約
expect_format_json = {
'$Like': {'k1': 'v1'}
}
2、python類契約帶引數
# python類契約
expect_format = Like({'k1': 'v1'}, nullable=True)
# json契約
expect_format_json = {
'$Like': {
# $values為契約類目標引數
'$values': {'k1': 'v1'},
# $params為額外引數的json資料
'$params': {'nullable': True}
}
}
4.根據響應結果自動生成 json 契約
from pactverify.utils import generate_pact_json_by_response
if __name__ == '__main__':
response_json = {
"msg": "success",
"code": 0,
"data": [{
"type_id": 249,
"name": "王者榮耀",
"order_index": 1,
"status": 1,
"subtitle": " ",
"game_name": "王者榮耀"
}, {
"type_id": 250,
"name": "絕地求生",
"order_index": 2,
"status": 1,
"subtitle": " ",
"game_name": "絕地求生"
}, {
"type_id": 251,
"name": "刺激戰場",
"order_index": 3,
"status": 1,
"subtitle": " ",
"game_name": "刺激戰場"
}
]
}
# 引數說明:響應json資料,契約關鍵字識別符號(預設$)
pact_json = generate_pact_json_by_response(response_json, separator='$')
print(pact_json)
'''
# 模板生成只會包含$EachLike、$Like,可以根據具體校驗需求更改,陣列取第一個元素為模板來生成
{
'$Like': {
'msg': 'success',
'code': 0,
'data': {
'$EachLike': {
'type_id': 249,
'name': '王者榮耀',
'order_index': 1,
'status': 1,
'subtitle': ' ',
'game_name': '王者榮耀'
}
}
}
}
'''
說明:
- PactVerify 與 PactJsonVerify 校驗類只是契約資料不同,其他邏輯保持一致
- PactJsonVerify 關鍵字標誌符可用 PactJsonVerify(separator='$') 自定義
四.基本匹配規則
1. Matcher 類
校驗規則:值匹配
# 預期11 python類契約格式
expect_format_1 = Matcher(11)
# 預期11 json契約格式
expect_format_json_1 = {
'$Matcher': 11
}
# 預期1.0 python類契約格式
expect_format_2 = Matcher(1.0)
# 預期1.0 json契約格式
expect_format_json_2 = {
'$Matcher': 1.0
}
# 預期'11' python類契約格式
expect_format_3 = Matcher('11')
# 預期'11' json契約格式
expect_format_json_3 = {
'$Matcher': '11'
}
# 預期返回資料actual為dict結構,actual['k1'] == 'v1' python類契約格式
expect_format_4 = Matcher({'k1': 'v1'})
# 預期返回資料actual為dict結構,actual['k1'] == 'v1' json契約格式
expect_format_json_4 = {
'$Matcher': {'k1': 'v1'}
}
2. Like 類
校驗規則:型別匹配
# 預期type(11) python類契約
expect_format_1 = Like(11)
# 預期type(11) json契約
expect_format_json_1 = {
'$Like': 11
}
# 預期type(1.0) python類契約
expect_format_2 = Like(1.0)
# 預期type(1.0) json契約
expect_format_json_2 = {
'$Like': 1.0
}
# 預期type('11') python類契約
expect_format_3 = Like('11')
# 預期type('11') json契約
expect_format_json_3 = {
'$Like': '11'
}
# 預期返回資料actual為dict結構,actual['k1'] == type('v1') python類契約
expect_format_4 = Like({'k1':'v1'})
# 預期返回資料actual為dict結構,actual['k1'] == type('v1') json契約
expect_format_json_4 = {
'$Like': {'k1':'v1'}
}
3. EachLike 類
校驗規則:陣列型別匹配
# 預期[type(11)] python類契約
expect_format_1 = EachLike(11)
# 預期[type(11)] json契約
expect_format_json_1 = {
'$EachLike': 11
}
# 預期[type(1.0)] python類契約
expect_format_2 = EachLike(1.0)
# 預期[type(1.0)] json契約
expect_format_json_2 = {
'$EachLike': 1.0
}
# 預期[type('11')] python類契約
expect_format_3 = EachLike('11')
# 預期[type('11')] json契約
expect_format_json_3 = {
'$EachLike': '11'
}
# 預期[Like{'k1':'v1'}] python類契約
expect_format_4 = EachLike({'k1': 'v1'})
# 預期[Like{'k1':'v1'}] json契約
expect_format_json_4 = {
'$EachLike': {'k1': 'v1'}
}
# 預期[Like{'k1':'v1'}]或[],minimum為陣列最小長度,預設minimum=1 python類契約
expect_format_5 = EachLike({'k1': 'v1'}, minimum=0)
# 預期[Like{'k1':'v1'}]或[],minimum為陣列最小長度,預設minimum=1 json契約
expect_format_json_5 = {
'$EachLike': {
# $values,$params結構用於額外傳參
'$values': {'k1': 'v1'},
'$params': {'minimum': 0}
}
}
4. Term 類
校驗規則:正則匹配
# 預期r'^\d{2}$',並且type(actual_data) == type(example),example也用來測試正規表示式 python類契約
expect_format_1 = Term(r'^\d{2}$', example=11)
# 預期r'^\d{2}$',並且type(actual_data) == type(example),example也用來測試正規表示式 json契約
expect_format_json_1 = {
'$Term': {
'$values': r'^\d{2}$',
'$params': {'example': 11}
}
}
# 預期r'^\d{2}$',example用來測試正規表示式,type_strict = False時跳過對example引數型別校驗 python類契約
expect_format_2 = Term(r'^\d{2}$', example="11", type_strict=False)
# 預期r'^\d{2}$',example用來測試正規表示式,type_strict = False時跳過對example引數型別校驗 json契約
expect_format_json_2 = {
'$Term': {
'$values': r'^\d{2}$',
'$params': {'example': 11, 'type_strict': False}
}
}
5. Enum 類
校驗規則:列舉匹配
# 預期11或22 python類契約
expected_format_1 = Enum([11, 22])
# 預期11或22 json契約
expected_format_json_1 = {
'$Enum': [11, 22]
}
# iterate_list為true時,當目標資料為陣列時,會遍歷陣列中每個元素是否in [11, 22] python類契約
expected_format_2 = Enum([11, 22], iterate_list=True)
# iterate_list為true時,當目標資料為陣列時,會遍歷陣列中每個元素是否in [11, 22] json契約
expected_format_json_2 = {
'$Enum': {
'$values': [11, 22],
'$params': {'iterate_list': True}
}
}
五.複雜規則匹配
1.{{}}格式
actual_data = {
'code': 0,
'msg': 'success',
'data': {
"id": 1,
"name": 'lili'
}
}
# python類契約
expect_format = Like({
'code': 0,
'msg': 'success',
'data': Like({
"id": 1,
"name": 'lili'
})
})
# json契約
expect_format_json = {
'$Like': {
'code': 0,
'msg': 'success',
'data': {
'$Like': {
"id": 1,
"name": 'lili'
}
}
}
}
2.[[]] 格式
actual_data = [[{
"id": 1,
"name": 'lili'
}]]
# python類契約
expect_format = EachLike(EachLike({
"id": 1,
"name": 'lili'
}))
# json契約
expect_format_json = {
'$EachLike': {
'$EachLike': {
"id": 1,
"name": 'lili'
}
}
}
3.{[]}格式
actual_data = {
'code': 0,
'msg': 'success',
'data': [{
"id": 1,
"name": 'lili'
},{
"id": 2,
"name": 'lilei'
}]
}
# python類契約
expect_format = Like({
'code': 0,
'msg': 'success',
'data': EachLike({
"id": 1,
"name": 'lili'
})
})
# json契約
expect_format_json = {
'$Like': {
'code': 0,
'msg': 'success',
'data': {
'$EachLike': {
"id": 1,
"name": 'lili'
}
}
}
}
4.Like-Term 巢狀
actual_data = {
'code': 0,
'msg': 'success',
'data': {
"id": 1,
"name": 'lili'
}
}
# python類契約
expect_format = Like({
'code': 0,
'msg': 'success',
'data': Like({
"id": 1,
"name": Term(r'\w*', example='lili')
})
})
# json契約
expect_format_json = {
'$Like': {
'code': 0,
'msg': 'success',
'data': {
'$Like': {
"id": 1,
"name": {
'$Term': {
'$values': r'\w*',
'$params': {
'example': 'lili'
}
}
}
}
}
}
}
5.Like-Matcher 巢狀
actual_data = {
'name': 'lilei',
'age': 12
}
# python類契約
expect_format = Like({
# name欄位值型別匹配
'name': 'lilei',
# age欄位值匹配
'age': Matcher(12),
})
# json契約
expect_format_json = {
'$Like': {
# name欄位值型別匹配
'name': 'lilei',
# age欄位值匹配
'age': {
'$Matcher': 12
},
}
}
說明:
- Matcher,Like 和 EachLike 類可以不限層級巢狀,Term 和 Enum 則不能巢狀其他規則
- 匹配規則多層巢狀時,內層規則優先生效
六.異常場景匹配
1.null 匹配
# nullable為true時允許返回null,預期null和(actual為dict結構,actual['k1'] == 'v1' or null)形式 python類契約
expect_format = Matcher({'k1': 'v1'}, nullable=True)
# nullable為true時允許返回null,預期null和(actual為dict結構,actual['k1'] == 'v1' or null)形式 json契約
expect_format_json = {
'$Matcher': {
'$values': {'k1': 'v1'},
'$params': {'nullable': True}
}
}
# nullable為true時允許返回null,預期null和(actual為dict結構,actual['k1'] == type('v1') or null)形式 python類契約
expect_format = Like({'k1': 'v1'}, nullable=True)
# nullable為true時允許返回null,預期null和(actual為dict結構,actual['k1'] == type('v1') or null)形式 json契約
expect_format_json = {
'$Like': {
'$values': {'k1': 'v1'},
'$params': {'nullable': True}
}
}
# nullable為true時允許返回null,預期null和[null,{'k1':null}]形式 python類契約
expect_format = EachLike({'k1': 'v1'}, nullable=True)
# nullable為true時允許返回null,預期null和[null,{'k1':null}]形式 json契約
expect_format_json = {
'$EachLike': {
'$values': {'k1': 'v1'},
'$params': {'nullable': True}
}
}
# nullable為true時允許返回null,預期null和11形式 python類契約
expect_format = Term(r'^\d{2}$', example=11, nullable=True)
# nullable為true時允許返回null,預期null和11形式 json契約
expect_format_json = {
'$Term': {
'$values': r'^\d{2}$',
'$params': {'example': 11, 'nullable': True}
}
}
# nullable為true時允許返回null,預期null和11/22/33形式 python類契約
expect_format = Enum([11, 22, 33], nullable=True)
# nullable為true時允許返回null,預期null和11/22/33形式 json契約
expect_format_json = {
'$Enum': {
'$values': [11, 22, 33],
'$params': {'nullable': True}
}
}
備註:nullable 引數在 hard_mode = True 時也生效
2.{}匹配
# dict_emptiable為true時,允許返回{},預期{}和(actual為dict結構,actual['k1'] == 'v1')形式 python類契約
expect_format = Matcher({'k1': 'v1'}, dict_emptiable=True)
# dict_emptiable為true時,允許返回{},預期{}和(actual為dict結構,actual['k1'] == 'v1')形式 json契約
expect_format_json = {
'$Matcher': {
'$values': {'k1': 'v1'},
'$params': {'dict_emptiable': True}
}
}
# dict_emptiable為true時,允許返回{},預期{}和(actual為dict結構,actual['k1'] == type('v1'))形式 python類契約
expect_format = Like({'k1': 'v1'}, dict_emptiable=True)
# dict_emptiable為true時,允許返回{},預期{}和(actual為dict結構,actual['k1'] == type('v1'))形式 json契約
expect_format_json = {
'$Like': {
'$values': {'k1': 'v1'},
'$params': {'dict_emptiable': True}
}
}
備註:dict_emptiable 在 hard_mode = True 時也生效
3.json 格式字串匹配
# actual為"{\"k1\":\"v1\"}"json字串格式時,先進行json.loads再校驗 python類契約
expect_format = Matcher({'k1': 'v1'}, jsonloads=True)
# actual為"{\"k1\":\"v1\"}"json字串格式時,先進行json.loads再校驗 json契約
expect_format_json = {
'$Matcher': {
'$values': {'k1': 'v1'},
'$params': {'jsonloads': True}
}
}
# actual為"{\"k1\":\"v1\"}"json字串格式時,先進行json.loads再校驗 python類契約
expect_format = Like({'k1': 'v1'}, jsonloads=True)
# actual為"{\"k1\":\"v1\"}"json字串格式時,先進行json.loads再校驗 json契約
expect_format_json = {
'$Like': {
'$values': {'k1': 'v1'},
'$params': {'jsonloads': True}
}
}
# actual為"[{\"k1\":\"v1\"}]"json字串格式時,先進行json.loads再校驗 python類契約
expect_format = EachLike({'k1': 'v1'}, jsonloads=True)
# actual為"[{\"k1\":\"v1\"}]"json字串格式時,先進行json.loads再校驗 json契約
expect_format_json = {
'$EachLike': {
'$values': {'k1': 'v1'},
'$params': {'jsonloads': True}
}
}
# actual為"[11,22]"json字串格式時,先進行json.loads再校驗 python類契約
expected_format = Enum([11, 22], jsonloads=True)
# actual為"[11,22]"json字串格式時,先進行json.loads再校驗 json契約
expected_format_json = {
'$Enum': {
'$values': {'k1': 'v1'},
'$params': {'jsonloads': True}
}
}
4.key 不存在匹配
# key_missable為true時,允許key不存在,key存在時走正常校驗;Matcher,Like,EachLike,Term和Enum類都可使用該屬性 python類契約
expect_format = Matcher({
'code': Like(0, key_missable=True),
'msg': Matcher('success', key_missable=True),
'data': EachLike(11, key_missable=True),
'age': Term(r'^\d{2}$', example=11, key_missable=True),
'num': Enum([11, 22, 33], key_missable=True)
})
# key_missable為true時,允許key不存在,key存在時走正常校驗;Matcher,Like,EachLike,Term和Enum類都可使用該屬性 json契約
expect_format_json = {
'$Matcher': {
'code': {
'$Like': {
'$values': 0,
'$params': {'key_missable': True}
}
},
'msg': {
'$Matcher': {
'$values': 'success',
'$params': {'key_missable': True}
}
},
'data': {
'$EachLike': {
'$values': 11,
'$params': {'key_missable': True}
}
},
'age': {
'$Term': {
'$values': r'^\d{2}$',
'$params': {'example': 11, 'key_missable': True}
}
},
'num': {
'$Enum': {
'$values': [11, 22, 33],
'$params': {'key_missable': True}
}
},
}}
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 python類契約
expected_format = Matcher({
'name': 'lilei',
'age': 12,
'sex': 'man'
}, dict_key_missable=True)
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 json契約
expected_format_json = {
'$Matcher': {
'$values': {
'name': 'lilei',
'age': 12,
'sex': 'man'
},
'$params': {'dict_key_missable': True}
}
}
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 python類契約
expected_format = Like({
'name': 'lilei',
'age': 12,
'sex': 'man'
}, dict_key_missable=True)
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 json契約
expected_format_json = {
'$Like': {
'$values': {
'name': 'lilei',
'age': 12,
'sex': 'man'
},
'$params': {'dict_key_missable': True}
}
}
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 python類契約
expected_format = EachLike({
'name': 'lilei',
'age': 12,
'sex': 'man'
}, dict_key_missable=True)
# dict_key_missable為true時,允許dict結構中的key不存在,但key不能多(hard_mode=true時),key存在時正常校驗 json契約
expected_format_json = {
'$EachLike': {
'$values': {
'name': 'lilei',
'age': 12,
'sex': 'man'
},
'$params': {'dict_key_missable': True}
}
}
5.多型別匹配
# actual資料為type(11)或type('11'),extra_types可以新增多個示例資料,對基礎資料型別(int,float,boolean,str,None)示例有效,對list dict等型別無效 python類契約
expect_format = Like(11, extra_types=['11'])
# actual資料為type(11)或type('11'),extra_types可以新增多個示例資料,對基礎資料型別(int,float,boolean,str,None)示例有效,對list dict等型別無效 json契約
expect_format_json = {
'$Like': {
'$values': 11,
'$params': {'extra_types': ['11']}
}
}
# actual資料為[type(11)]或[type('11')],extra_types可以新增多個示例資料,對基礎資料型別示例(int,float,boolean,str,None)有效,對list dict等型別無效 python類契約
expect_format = EachLike(11, extra_types=['11'])
# actual資料為[type(11)]或[type('11')],extra_types可以新增多個示例資料,對基礎資料型別示例(int,float,boolean,str,None)有效,對list dict等型別無效 json契約
expect_format_json = {
'$EachLike': {
'$values': 11,
'$params': {'extra_types': ['11']}
}
}
6.非強制欄位匹配
expect_format = Like({'k1': 'v1'})
# hard_mode=False只匹配契約中定義的欄位,實際返回的多餘欄位忽略 python類契約
mPactVerify = PactVerify(expect_format, hard_mode=False)
actual_data = {'k1': 'v1', 'k2': 'v2'}
# 只校驗k1欄位,k2欄位忽略
mPactVerify.verify(actual_data)
expect_format_json = {
'$Like': {'k1': 'v1'}
}
# hard_mode=False只匹配契約中定義的欄位,實際返回的多餘欄位忽略 json契約
mPactJsonVerify = PactJsonVerify(expect_format, hard_mode=False)
actual_data = {'k1': 'v1', 'k2': 'v2'}
# 只校驗k1欄位,k2欄位忽略
mPactJsonVerify.verify(actual_data)
備註:
1. key_missable 在 hard_mode = True 時也生效
2. key_missable 針對 actual_data 本身的 key,dict_key_missable 針對 actual_data 字典中的 key,可以同時生效
注意:異常匹配場景越多,代表介面資料格式越不規範
七.配合 unittest+requests 使用
import unittest, requests, HtmlTestRunner, os
from pactverify.matchers import Matcher, Like, EachLike, Term, Enum, PactVerify
class PactTest(unittest.TestCase):
def test_config_2(self):
url = 'http://127.0.0.1:8080/configV2'
config_rsp = requests.get(url)
config_contract_format = Matcher({
"msg": "success",
"code": 200,
'name': Enum(['lili', 'xiaohei']),
'addr': Term(r'深圳*', example='深圳寶安'),
"data": EachLike({
"type_id": 249,
"name": "王者榮耀",
"order_index": 1,
"status": 1,
"subtitle": " ",
"game_name": "王者榮耀"
}),
'data_2':
EachLike({
"type_id": 249,
"name": "王者榮耀",
"order_index": 1,
"status": 1,
"subtitle": " ",
"game_name": "王者榮耀"
}, minimum=1)
})
mPactVerify = PactVerify(config_contract_format)
try:
actual_rsp_json = config_rsp.json()
mPactVerify.verify(actual_rsp_json)
assert mPactVerify.verify_result == True
except Exception:
# 自定義錯誤資訊,輸出到HTMLTestRunner中
err_msg = 'PactVerify_fail,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,
mPactVerify.verify_info)
self.fail(err_msg)
if __name__ == '__main__':
current_path = os.path.abspath(__file__)
current_dir = os.path.abspath(os.path.dirname(current_path) + os.path.sep + ".")
suite = unittest.defaultTestLoader.discover(current_dir, pattern="test_*.py")
runner = HtmlTestRunner.HTMLTestRunner(combine_reports=True, report_name="MyReport", add_timestamp=False)
runner.run(suite)
八.優點總結
1.顯式定義介面斷言格式,介面斷言更加直觀
2.可複用介面實際響應資料來定義契約
相關文章
- 介面自動化測試,一鍵快速校驗介面返回值全部欄位
- pydantic 欄位欄位校驗
- 黃反詞介面 詞典自動化校驗
- 使用hibernate校驗欄位
- 全自動化介面
- WTForms 欄位 引數 校驗ORM
- ThinkPHP3.2.3 欄位對映/自動驗證/自動完成PHP
- vue: el-form只校驗部分欄位VueORM
- 實現註解校驗Dto欄位是否為空
- mybatisplus欄位值自動填充MyBatis
- 技術必備:推薦一款介面自動化測試資料校驗神器
- mybatis自動填充時間欄位MyBatis
- thinkphp validate unique 資料庫欄位唯一性校驗PHP資料庫
- 【EF Core】自動生成的欄位值
- Httpclient 介面自動化HTTPclient
- python 介面自動化Python
- 【Django drf】 序列化類常用欄位類和欄位引數 定製序列化欄位的兩種方式 關係表外來鍵欄位的反序列化儲存 序列化類繼承ModelSerializer 反序列化資料校驗原始碼分析Django繼承原始碼
- 介面自動化與ui自動化區別UI
- 給mybatis新增自動建表,自動加欄位的功能MyBatis
- 時間序列的ADF校驗(單位根校驗)
- 在 Laravel 中自動維護 slug 欄位Laravel
- springboot~jpa審計欄位的自動填充Spring Boot
- Laravel 專案全自動介面管理(介面部分)Laravel
- 介面自動化測試
- 欄位管理,為什麼只有新增的時候才自動匹配欄位型別型別
- 介面自動化之介面整理(抓包)
- 如何自動填充SQL語句中的公共欄位SQL
- 如何給SAP Cloud for Customer UI上的欄位新增自定義校驗邏輯CloudUI
- 介面測試-引數校驗
- 前端資料校驗後,後端介面是否需要再次校驗?前端後端
- Python 介面自動化測試Python
- JMeter 介面自動化測試(手工轉自動化指令碼)JMeter指令碼
- 【vue3+vue2】清除ElementUI的el-input標籤的校驗-區別——resetFields()-移除校驗結果並重置欄位值 & clearValidate()-移除校驗結果VueUI
- mybatis自動填充多個表相同欄位的值MyBatis
- MyBatis-Plus-實用的功能自動填充欄位MyBatis
- 【mybatis-plus】主鍵id生成、欄位自動填充MyBatis
- SMSSDK驗證碼服務端校驗介面服務端
- 介面自動化的關鍵思路和解決方案,本文全講清楚了