httprunner如何提取數據串聯上下游接口

httprunner進行接口測試時,從上一個接口提取參數傳遞給下游接口,如何獲取數據裏最後一個值?html

忽然被學員問道一個httprunner的問題,慚愧的是大貓以前沒有是經過httprunner,又很差意思說不會,只能硬着頭皮去看源碼了。python

 

問題其實很簡單,怎麼處理我無論,反正你得給答案。看一眼同窗反饋的截圖,確實不難,問題很簡單。請求某一個接口,接口返回的content裏包含多個字段,須要獲取到最後一個字典裏的數據。是否是以爲很簡單?git

 

 

對於這麼具體的問題,大貓固然是第一反應去百度啦!固然,若是能簡單百度到答案,學員也不會來問我,所以,結果可想而知,百度沒有標準答案!github

 

 

不過百度一點用處也沒有麼,也不盡然,至少對於一隻歷來沒有使用過httprunner的大貓來講,知道從響應提取數據使用extract關鍵字。正則表達式

既然百度沒有標準答案,咱們就代碼裏找,大貓最不怕的就是看代碼,大江大浪都走過來了,還能這幾千行代碼裏翻船?json

看代碼先要去github把代碼拉取到本地(這裏就不寫怎麼作了),用pycharm打開,而後使用pycharm的「find in path...」進行全局查找,像這樣:微信

咱們點擊去看下代碼的實現細節,沒準能夠發現蛛絲馬跡。cookie

if not extractors:
return {}

logger.log_debug("start to extract from response object.")
extracted_variables_mapping = OrderedDict()
extract_binds_order_dict = utils.ensure_mapping_format(extractors)

for key, field in extract_binds_order_dict.items():
extracted_variables_mapping[key] = self.extract_field(field)

return extracted_variables_mapping
app

代碼實現至關簡潔,實例化一個OrderedDict用於存儲提取後的數據,採用extract_field函數來執行具體的提取數據操做。咱們接着看extract_field函數。框架

text_extractor_regexp_compile = re.compile(r".*\(.*\).*")

if text_extractor_regexp_compile.match(field):
value = self._extract_field_with_regex(field)
else:
value = self._extract_field_with_delimiter(field)

extract_field的核心邏輯也很是簡潔,採用re.compile判斷表達式是否爲正則,是的話執行正則表達式提取_extract_field_with_regex,若是不是正則採用分隔符提取方式,_extract_field_with_delimiter,咱們須要的是分隔符方式提取,所以看_extract_field_with_delimiter函數的實現。

_extract_field_with_delimiter函數實現略微複雜,函數裏對查詢字符串進行了分級處理,content.person.name.first_name被分紅top_query:content和sub_query:[person, name, first_name]。

同時不一樣的top_query有不一樣的處理方法,例如top_query如果status_code,encoding,ok,reason,url等則不能有sub_query,不然會拋出異常(這裏和響應對象結構有關係);

if top_query in ["status_code", "encoding", "ok", "reason", "url"]:
if sub_query:
# status_code.XX
err_msg = u"Failed to extract: {}\n".format(field)
logger.log_error(err_msg)
raise exceptions.ParamsError(err_msg)

return getattr(self, top_query)

對於top_query是cookies和headers的處理,若存在sub_query則以sub_query爲key進行取值,不然返回cookie或header總體。

elif top_query == "cookies":
cookies = self.cookies
if not sub_query:
# extract cookies
return cookies

try:
return cookies[sub_query]
except KeyError:
err_msg = u"Failed to extract cookie! => {}\n".format(field)
err_msg += u"response cookies: {}\n".format(cookies)
logger.log_error(err_msg)
raise exceptions.ExtractFailure(err_msg)

若是top_query是content,text或json則使用query_json函數進一步處理。固然,處理前進行了一次判斷,sub_query是字典、列表仍是數字。

elif top_query in ["content", "text", "json"]:
try:
body = self.json
except exceptions.JSONDecodeError:
body = self.text

if not sub_query:
# extract response body
return body

if isinstance(body, (dict, list)):
# content = {"xxx": 123}, content.xxx
return utils.query_json(body, sub_query)
elif sub_query.isdigit():
# content = "abcdefg", content.3 => d
return utils.query_json(body, sub_query)
else:
# content = "<html>abcdefg</html>", content.xxx
err_msg = u"Failed to extract attribute from response body! => {}\n".format(field)
err_msg += u"response body: {}\n".format(body)
logger.log_error(err_msg)
raise exceptions.ExtractFailure(err_msg)

query_json函數是實現取值的關鍵,函數使用分隔符講sub_query切分紅字符串數據,採用循環遍歷數據。

for key in query.split(delimiter):
if isinstance(json_content, (list, basestring)):
json_content = json_content[int(key)]    <- 這裏是關鍵
elif isinstance(json_content, dict):
json_content = json_content[key]
else:
logger.log_error(
"invalid type value: {}({})".format(json_content, type(json_content)))
raise_flag = True

這裏若是數據是列表則將key轉化爲數字取值,不然認爲是字典直接用key取值。既然代碼是轉化成整形,整數有正整數,負整數和零,理論上提取數據的字符串能夠有content.person.-1.name.first_name

這樣的存在。這裏能夠理解爲從content裏取最後一個person的name的first_name。

 

另外,這裏多說一句,能夠看見httprunner的代碼並不難python測開的學員應該都能看到懂,但願你們多看看開源框架的代碼,提高本身的代碼能力,也但願你們報名個人課程。

做  者:Testfan 大貓

出  處:微信公衆號:自動化軟件測試平臺

版權說明:歡迎轉載,但必須註明出處,並在文章頁面明顯位置給出文章連接

相關文章
相關標籤/搜索