RPC接口測(cè)試技術(shù)-Tcp 協(xié)議的接口測(cè)試
首先明確 Tcp 的概念,針對(duì) Tcp 協(xié)議進(jìn)行接口測(cè)試,是指基于 Tcp 協(xié)議的上層協(xié)議比如 Http ,串口,網(wǎng)口, Socket 等。這些協(xié)議與 Http 測(cè)試方法類似(具體查看接口自動(dòng)化測(cè)試章節(jié)),但在測(cè)試過(guò)程中需要做些調(diào)整。
Socket
Socket 又稱套接字,進(jìn)程可通過(guò)套接字進(jìn)行網(wǎng)絡(luò)通信,使多個(gè)設(shè)備具有交互能力。Socket 適合對(duì)傳輸速度和安全性有嚴(yán)格要求的應(yīng)用,比如手機(jī)內(nèi)核與外界進(jìn)行測(cè)試數(shù)據(jù)的傳輸。支持 Socket 設(shè)備不止計(jì)算機(jī),還會(huì)有移動(dòng)端,如果測(cè)試 Socket 協(xié)議,需要有收發(fā) Socket 數(shù)據(jù)的能力或代理 Socket 的能力。
下圖展示了正常的 Socket 通信流程:

如果測(cè)試 Socket 協(xié)議,需要做以下改造,即利用 Socket 代理,進(jìn)行 Socket 數(shù)據(jù)的接收:

需要特別注意,需要應(yīng)用可更改 Socket 地址,才可使用代理。以 Python 的 Socket 為例,下面是一個(gè)簡(jiǎn)單的 Socket 客戶端和服務(wù)端:
# 客戶端
import socket ? ? ? ? ? ? ? # 導(dǎo)入 socket 模塊
s = socket.socket() ? ? ? ? # 創(chuàng)建 socket 對(duì)象
host = '127.0.0.1' ? ? ? ? ?# 獲取本地主機(jī)名
port = 12345 ? ? ? ? ? ? ? ?# 設(shè)置端口號(hào)
s.connect((host, port))
print(s.recv(1024).decode())
s.close()
# 服務(wù)端
import socket ? ? ? ? ? ? ? # 導(dǎo)入 socket 模塊
s = socket.socket() ? ? ? ? # 創(chuàng)建 socket 對(duì)象
host = '127.0.0.1' ? ? ? ? ?# 獲取本地主機(jī)名
port = 12345 ? ? ? ? ? ? ? ?# 設(shè)置端口
s.bind((host, port)) ? ? ? ?# 綁定端口
s.listen(5) ? ? ? ? ? ? ? ? # 等待客戶端連接
while True:
? ?c,addr = s.accept() ? ? # 建立客戶端連接
? ?print(addr)
? ?c.send('收到信息'.encode())
? ?c.close() ? ? ? ? ? ? ? ?# 關(guān)閉連接
客戶端可與服務(wù)端進(jìn)行交流,但 Socket 地址不可更改,即上述客戶端代碼的 127.0.0.1 和 12345 端口不能通過(guò)配置文件進(jìn)行更改。如果不能更改這兩者,就堵死了通向代理的道路:

如何進(jìn)行修改?以客戶端代碼為例,可通過(guò)配置文件來(lái)配置 host 和 port :
import socket
import yaml
# 通過(guò)配置文件,進(jìn)行 host 和 port 配置
with open("config.yaml","r", encoding="utf-8") as f:
? ?data = yaml.safe_load(f)
host = data.get("host")
port = data.get("port")
s = socket.socket()
s.connect((host, port))
print(s.recv(1024).decode())
s.close()
config.yaml 的內(nèi)容如下:
host: "127.0.0.1"
port: 12345
上述更改,可使應(yīng)用走 Socket 代理。測(cè)試人員還需一款合適的代理工具,推薦 mitmproxy 或自寫(xiě) Socket 代理。mitmproxy 使用請(qǐng)參考:
mitmproxy 官網(wǎng):https://www.mitmproxy.org/ 1
其他協(xié)議
其它協(xié)議,比如串口、網(wǎng)口、visa 等,與 Socket 的測(cè)試模式類似,用相同的圖即可簡(jiǎn)述:

其它協(xié)議較 Sokcet 更冷門,無(wú)合適的代理工具。需要測(cè)試人員自己寫(xiě)代理,比如串口協(xié)議, Python 雖然支持 Pyserial 進(jìn)行收發(fā)串口,但無(wú)代理。此時(shí)需要測(cè)試人員自行編寫(xiě)串口代理工具。這個(gè)過(guò)程需要開(kāi)啟兩個(gè)監(jiān)聽(tīng)服務(wù),如下圖,監(jiān)聽(tīng)服務(wù) A 監(jiān)聽(tīng)端口 123 ,如果有數(shù)據(jù)進(jìn)來(lái),會(huì)透?jìng)鳎ɑ蜃鰯?shù)據(jù)更改,實(shí)現(xiàn) mock)給端口 456,監(jiān)聽(tīng)服務(wù) B 同理:

使用兩個(gè)監(jiān)聽(tīng)服務(wù),可編寫(xiě)任意協(xié)議,但注意缺點(diǎn),數(shù)據(jù)的傳輸時(shí)間會(huì)增加,如果過(guò)分注重性能,此方案慎用。下面是參考代碼,其中只保留了關(guān)鍵邏輯:
def forward(self):
? ?"""
? ?開(kāi)啟監(jiān)聽(tīng)
? ?:return:
? ?"""
? ?while True:
? ? ? ?# 從虛擬串口接收到請(qǐng)求
? ? ? ?virtual_req = self.virtual_ser.recv()
? ? ? ?if b'' == virtual_req:
? ? ? ? ? ?continue
? ? ? ?if self.is_call_back:
? ? ? ? ? ?# 返回空值,讓 mock_server 決定返回內(nèi)容
? ? ? ? ? ?real_result = b""
? ? ? ?else:
? ? ? ? ? ?# 等待真實(shí)設(shè)備出現(xiàn)
? ? ? ? ? ?if self.real_ser is None :
? ? ? ? ? ? ? # 代碼省略
? ? ? ? ? ?# 將請(qǐng)求轉(zhuǎn)發(fā)到真實(shí)串口
? ? ? ? ? ?real_result = self.real_ser.write_by_bytes(virtual_req)
? ? ? ?# 獲取 mock 的結(jié)果,在此可以加入 mock 操作
? ? ? ?mock_result = self.mock_server.mock(virtual_req, real_result)
? ? ? ?# 將 mock 結(jié)果寫(xiě)入虛擬串口
? ? ? ?self.virtual_ser.send(mock_result)
再次強(qiáng)調(diào),需要讓?xiě)?yīng)用支持端口修改,才能使用代理工具,這部分需要與開(kāi)發(fā)交流,提修改需求。