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 大猫

出  处:微信公众号:自动化软件测试平台

版权说明:欢迎转载,但必须注明出处,并在文章页面明显位置给出文章连接

相关文章
相关标签/搜索