引言
笔者,在非常繁忙的工作之余,决定抽时间记录一下在测试接口时所遇到的问题,以便日后参考,也可以提供给那些正在学习的接口测试的伙伴参考,避免走弯路。如果对您有帮忙,点个赞,谢谢。
今天这篇文章主要是讲接口测试中请求参数包含转义字符的和返回参数包含转义字符的处理
1、首先,看一下我的接口中入参的数据样式:
这个body中的参数有两个“body”和“method”,整个data变量是一个字典,但是“body”是个字符串,并且是包含转义字符,整个就是一个转义字符串。这种参数写代码里面是没问题的,但是作为接口请求时,有时候无法被json解析,最终导致接口请求失败。
这种参数,不处理,直接去请求,就像下图所示:
2、目标已经确定,接下来就是处理了,我先将data数据反转义,其实很简单,用的是json的一个方法loads(),如图:
在用这个方法时,还要提前处理一下data,因为该方法支持类型有限制,如:
def loads(s, *, encoding=None, cls=None, object_hook=None, parse_float=None,
parse_int=None, parse_constant=None, object_pairs_hook=None, **kw):
"""Deserialize ``s`` (a ``str``, ``bytes`` or ``bytearray`` instance
containing a JSON document) to a Python object.
``object_hook`` is an optional function that will be called with the
result of any object literal decode (a ``dict``). The return value of
``object_hook`` will be used instead of the ``dict``. This feature
can be used to implement custom decoders (e.g. JSON-RPC class hinting).
``object_pairs_hook`` is an optional function that will be called with the
result of any object literal decoded with an ordered list of pairs. The
return value of ``object_pairs_hook`` will be used instead of the ``dict``.
This feature can be used to implement custom decoders that rely on the
order that the key and value pairs are decoded (for example,
collections.OrderedDict will remember the order of insertion). If
``object_hook`` is also defined, the ``object_pairs_hook`` takes priority.
``parse_float``, if specified, will be called with the string
of every JSON float to be decoded. By default this is equivalent to
float(num_str). This can be used to use another datatype or parser
for JSON floats (e.g. decimal.Decimal).
``parse_int``, if specified, will be called with the string
of every JSON int to be decoded. By default this is equivalent to
int(num_str). This can be used to use another datatype or parser
for JSON integers (e.g. float).
``parse_constant``, if specified, will be called with one of the
following strings: -Infinity, Infinity, NaN.
This can be used to raise an exception if invalid JSON numbers
are encountered.
To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
kwarg; otherwise ``JSONDecoder`` is used.
The ``encoding`` argument is ignored and deprecated.
"""
|
我先将data转成str,如图:
之所以贴个报错的截图,这里有个知识点,教给大家。
python字符串是有层次的,比如使用''' '''和" "和‘ ’,所以不能像上图那样使用两个" "。
修改之后,执行调用接口程序:
这个返回结果就是我想要的。
入参的转义讲完,那么出参的呢? 留给大家思考。
编码处理
很多时候返回的数据中,有中文和二进制数据,先看一下接口返回的未处理的数据,显示如下:
这种数据,第一不方便查看,第二很难找到自己想要的值。
print(r2.content.decode(),end=' ')
|
运行脚本:
UnicodeEncodeError: 'gbk' codec can't encode character '\xe2' in position 15788: illegal multibyte sequence
|
这句话说的是gbk无法encode编码,但是我代码编码是utf-8,显然不是代码问题。错误位置在'\xe2'是无法被解码。加一下标准输出代码:
import io
import sys
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030') #改变标准输出的默认编码
|
再次执行程序,结果显示成功:
需要注意的是,如果gb18030不行的话,就用utf-8,如:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf8') #改变标准输出的默认编码
|
还可以改成:
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='gbk')
|
下面是一些中文对应的编码表格:
编码名称
| 用途
|
utf8
| 所有语言
|
gbk
| 简体中文
|
gb2312
| 简体中文
|
gb18030
| 简体中文
|
big5
| 繁体中文
|
big5hkscs
| 繁体中文
|
原因说明:对于Unicode字符,需要print出来的话,由于本地系统是Windows中的cmd,默认codepage是CP936,即GBK的编码,所以python解释器需要先将上述的Unicode字符编码为GBK,然后再在cmd中显示出来。但是由于该Unicode字符串中包含一些GBK中无法显示的字符,导致此时提示“’gbk’ codec can’t encode”的错误的。其实print()函数的局限就是Python默认编码的局限,因为系统是windows的,python的默认编码不是'utf-8',改一下python的默认编码成'utf-8'就行了。
接口请求方式
引言中已经说过,如果对requests请求不了解,可以参考我的这篇文章Python 接口测试requests.post方法中data与json参数区别。这篇文章讲过post请求的两种数据类型data和json,那么针对body数据中有转义字符的数据,如何同时使用这两种参数类型请求呢?在讲之前,先复习一下知识点:
resp.text返回的是Unicode型的数据。
resp.content返回的是bytes型的数据。
resp.json()返回的是json格式数据
#备注:
#如果你想取文本,可以通过r.text。
#如果想取图片,文件,则可以通过r.content。
#如果想要dict类型的数据,则可以通过r.json()。
|
具体脚本:
结果如下:
不管你选择data类型和json类型,只要传参的类型对应上就完全没问题。这里没有直接贴脚本代码,也是让初学者自己动手敲,不能直接Copy用,这样对自己编码提升会有阻碍。
提取报文中参数
如何取出返回结果中的key对应的values,比如这个接口我是要获取warehouseName这个字段的值,如图:
从数据上看,返回的数据类型是字典,而我要获取的字典warehouseName是在字典中data里,data 是字典,里面还有个列表,列表中也有个字典,等于嵌套了4层,如何取出4层的中里面值呢?这要分两步操作,具体请看代码:
# 取出字典中的key对应的值
a = r.json()
b =a['data']['wimslist']
# print(type(dict(b)))
c = json.dumps(b, ensure_ascii=False)
# 方法1
for item in b:print (item['warehouseName'],end=' ')
# 方法2
# 获取list中字典的key值
list_result = []
for i in b:
list_result.append(i['warehouseName'])
print(list_result)
from common.loggers import Log
loggger = Log()
|
输出结果如下:
附录
1、这里贴出关于(字符串前面u,r,b)的知识点,加深印象,如果没有了解过,就当学习一下,以后自然会用到。
1、字符串前加 u
例:u"我是含有中文字符组成的字符串。"
作用:
后面字符串以 Unicode 格式 进行编码,一般用在中文字符串前面,防止因为源码储存格式问题,导致再次使用时出现乱码。
2、字符串前加 r
例:r"\n\n\n\n” # 表示一个普通生字符串 \n\n\n\n,而不表示换行了。
作用:
去掉反斜杠的转义机制。
(特殊字符:即那些,反斜杠加上对应字母,表示对应的特殊含义的,比如最常见的”\n”表示换行,”\t”表示Tab等。 )
应用:
常用于正则表达式,对应着re模块。
3、字符串前加 b
例: response = b'<h1>Hello World!</h1>' # b' ' 表示这是一个 bytes 对象
作用:
b" "前缀表示:后面字符串是bytes 类型。
用处:
网络编程中,服务器和浏览器只认bytes 类型数据。
如:send 函数的参数和 recv 函数的返回值都是 bytes 类型
附:
在 Python3 中,bytes 和 str 的互相转换方式是
str.encode('utf-8')
bytes.decode('utf-8')
|
2、关于python编码基础知识,字符串和字节流之间转换如下图: