引言
筆者,在非常繁忙的工作之余,決定抽時間記錄一下在測試接口時所遇到的問題,以便日后參考,也可以提供給那些正在學習的接口測試的伙伴參考,避免走彎路。如果對您有幫忙,點個贊,謝謝。
今天這篇文章主要是講接口測試中請求參數包含轉義字符的和返回參數包含轉義字符的處理,之前關於接口測試方法
可以參考Python 接口測試requests.post方法中data與json參數區別。
處理入參有轉義字符的接口
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編碼基礎知識,字符串和字節流之間轉換如下圖:

相關詳情可以參考我的另一篇文章:https://www.cnblogs.com/liudinglong/p/12588019.html
如果對python測試開發相關技術感興趣的伙伴,歡迎加入測試開發學習交流QQ群:696400122,不積跬步,無以至千里。
