寫在前面
RF自動化的文章記錄基本完成,建一個匯總目錄,方便查看。
【Robot Framework 項目實戰】匯總
∮【RF 項目實戰 01】使用 RequestsLibrary 進行接口測試
∮【RF 項目實戰 03】使用腳本自動生成統一格式的RF自動化用例
∮【RF 項目實戰 04】基於錄制生成RF關鍵字及基礎自動化用例
腳本優化
上一篇博客我們編寫了基於錄制生成的RF自動化Demo用例,但是只是完全根據抓包數據構造了一條正常的測試用例,其實針對接口的參數校驗這樣的重復性比較強的測試,我們也可以把它們腳本化,參數化到RF文件中。
接口測試,基本參數校驗范圍
基本參數校驗,是每次接口測試首要考慮的內容,這部分應當是測試工程師的基本能力。
- 可選與必選:
- 字段可選,傳與不傳時的區別
- 字段必選,必選參數缺失時返回什么錯誤,返回格式是否標准
- 空值:
- 空值時,返回什么結果。(如網絡超時未返回,當成空值在處理還是默認值處理)
- 默認值:
- 是否有默認值,可選參數和必選參數是否有默認值
- 類型:
- int,區分32和64位,int類型時,傳str時的錯誤展示
- string類型,
- float類型,往往在計算金額時,會用到浮點數
- 類型長度:
- 超過長度,接口請求是否出錯,如果不出錯,展示是否被截斷
- 中文跨越邊界時被截斷的問題,如nickname是32字節,共16個中文,前15是中文,第16是英文,第17是中文,則多出一個字節,最后一個中文是否被截斷顯示為亂碼
- 大小寫:
- 是否大小寫敏感,signkey,等內容,一般大小寫敏感
- 安全過濾:
- <>是否被過濾掉,是否有直接存寫到DB
- ' " 是否被轉譯或者使用防SQL注入的ORM組件
- 編碼類型:
- utf-8,GBK,unicode
- 特殊字符(空格,換行等),emoji(4個字節),中文,拉丁文,日文等
具體實現
首先我們定義一批可能需要傳遞的參數,使用常量的方式存儲。
PARAM_ERR = 10000
OK = 0
BOOL = True # False
INT = 10
NEG_INT = -1
ZERO = 0
BIG_INT = 99**5
NEG_FLOAT = -1.1
FLOAT = 0.99
EMPTY_STR = ""
INT_STR = "1111"
LETTERS_STR = "ABCabc"
SPACE_STR = " "
EMPTY_LIST = []
STR_LIST = ["a", "b"]
INT_LIST = [10, 20]
BOOL_LIST = [True, False]
MIX_LIST = ["a", True, 10, ["aa"], {"a": "aa"}]
EMPTY_DICT = {}
STR_DICT = {"a": "b"}
INT_DICT = {"d": 11}
BOOL_DICT = {"c": True}
MIX_DICT = {"b": "", "c": True, "d": 11, "e": {"f": [1, 2]}}
...
然后我們通過原始的請求參數,自己組裝不同的請求參數:
def gen_req_data(sheet_obj):
str_params = sheet_obj.cell_value(1, 1)
str_method = sheet_obj.cell_value(1, 6)
temp_list = []
# print(f"str_params:{str_params}")
if not len(str_params):
return ""
try:
# 轉化 json類型為Python標准類型
params = eval(str_params.replace("false", "False").replace("true", "True").replace("null", "None"))
if not len(params):
return ""
except Exception as f:
logger.warning("====================================================")
logger.error("=" + str(f))
logger.warning("====================================================")
params = ""
# 正常參數
temp_list.append(params)
# 添加異常參數
for k, v in params.items():
if isinstance(v, dict):
for i in [
BOOL,
NEG_FLOAT,
LETTERS_STR,
MIX_LIST,
ZERO,
MIX_DICT
]:
params = copy.deepcopy(params) # 深拷貝,字典存儲的是內存地址
params[k] = i # doc
temp_list.append(params)
elif isinstance(v, list):
for i in [BOOL, NEG_FLOAT, LETTERS_STR, MIX_LIST, ZERO, MIX_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, str):
for i in [BOOL, NEG_FLOAT, EMPTY_STR, INT_STR, SPACE_STR, MIX_DICT, STR_LIST, EMPTY_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, int):
for i in [BOOL, NEG_FLOAT, INT_STR, INT_LIST, NEG_INT, ZERO, BIG_INT, NEG_FLOAT, FLOAT, EMPTY_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
elif isinstance(v, bool):
for i in [True, False, ZERO, FLOAT, NEG_INT, INT_STR, INT_LIST, STR_DICT]:
params = copy.deepcopy(params)
params[k] = i
temp_list.append(params)
return str_method, temp_list
最后,我們把不同的請求參數轉化為RF測試用例需要的數據格式,最終生成對應的測試用例:
def gen_testcase(self, sheet_obj, target_robot_name, interface_name):
"""
:param sheet_obj:
:param target_robot_name:
:param interface_name:
:return:
"""
method, params_list = self.gen_req_data(sheet_obj)
with open(target_robot_name, 'a') as f:
for num, param in enumerate(params_list):
"""
待辦:動態修改Documentation的信息,異常參數以tuple的形式存儲Documentation,然后解析的時候參數化到文檔中
"""
f.write(interface_name + f'.Demo_case{num}' + '\n')
f.write(' [Documentation] demo' + '\n')
f.write(' [Tags] ' + self.tag + '\n')
params = self._gen_param_data(method, param)
f.write(params)
if params:
f.write(' ${{Resp_data}} {}'.format(self.project_abbr) + interface_name + ' ${HOST} ' + "${param}")
else:
f.write(' # 未獲取到請求參數數據 \n')
f.write(' ${{Resp_data}} {}'.format(self.project_abbr) + interface_name + ' ${HOST} ' + "${EMPTY}")
f.write('\n')
f.write(' Log ${Resp_data.text}' + '\n')
# 第一條用例正常斷言,其他用例標記為失敗用例
if num == 0:
f.write(' Should Be Equal As Strings ${Resp_data.status_code} 200' + '\n')
f.write(' ${resp_json} to json ${Resp_data.text}' + '\n')
f.write(self.gen_exp_data(sheet_obj))
else:
f.write(f' Should Be Equal As Strings ${{Resp_data.status_code}} {self.error_status_code}' + '\n')
f.write(' ${resp_json} to json ${Resp_data.text}' + '\n')
f.write(self._format_exp_data(self.param_error_json)) # param_error_json 接口異常返回內容中的公共部分,比如code, result
f.write('\n')
logger.info("Demo case保存於:" + target_robot_name)
注:⚠️ 部分依賴代碼在上一篇文章中可以找到。
總結
通過抓包,我們獲取了原始數據,然后根據抽象異常參數傳遞校驗的方式,把接口測試異常用例抽取了出來,這個不管是在手工測試過程中,還是在自動化過程中都非常的有用,能節省大量的人力成本。
當然這個方式也有一定的局限性,需要整個團隊來配置,比如腳本中使用到的param_error_json
就是因為博主所在項目組有比較規范的接口返回定義才能做這樣的統一斷言。