測試socket接口
接口測試時,除了常見的http接口,還有一種比較多見,就是socket接口,今天講解下怎麼用Python自帶的socket庫進行socket接口測試。
我們就用之前搭建的測試框架來實現。具體可見 從零搭建自動化測試框架系列
1. socket接口
socket
又叫 套接字
,可以理解爲是一個應用程序的地址,是實現網絡通信的關鍵。我們可以通過IP找到一臺主機,可以通過主機的端口找到該主機上的某個應用程序。
這樣,就可以通過socket進行兩個應用程序之間的通信。具體實現就是在一端實現一個一直在監聽的server,另一端向其發送請求,並獲取響應。server對不同的請求進行不同的處理並返回,這就是socket接口。
下面我們就實現一個socket的接口並對其進行測試。
2. 實現一個socket server接口
在test下創建mock文件夾,並在其中創建mock_socket_server.py文件:
"""
socket server 的mock。
兩個接口,add和sub
接收:
{
"action": "add",
"params": {"a": 1, "b": 2}
}
返回:
{
"action": "add",
"result": 3
}
"""
import socket
import json
def add(a, b):
return a + b
ip_port = ('127.0.0.1', 8080)
server = socket.socket()
server.bind(ip_port)
server.listen(5)
while True:
conn, addr = server.accept()
data = conn.recv(1024)
try:
ddata = json.loads(data)
action = ddata.get('action')
params = ddata.get('params')
if action == 'add':
res = add(**params)
conn.send(b'{"action": "add", "result": %d}' % res)
else:
conn.send(b'{"code":-2, "message":"Wrong Action"}')
except (AttributeError, ValueError):
conn.send(b'{"code":-1, "message":"Data Error"}')
finally:
conn.close()
我們就實現了一個簡單的socket server,有一個接口add。開發給你的接口文檔可能是這樣的:
接口類型: socket
接口地址: 127.0.0.1
端口: 8080
接口名稱: 加法
action name: add
入參:
名稱 類型 是否必須 a int 是 b int 是 出參:
名稱 類型 含義 result int 結果 入參示例:
{ "action": "add", "params": {"a": 1, "b": 2} }
出參示例:
{ "action": "add", "result": 3 }
error code:
code message -1 Data Error -2 Wrong Action
拿到接口文檔,接下來我們該怎麼進行測試呢?
3. 測試socket接口
首先我們需要一個通用的client類,把socket接口測試通用的方法封裝起來,免得每次都得寫一堆。在client.py中添加TCPClient
class TCPClient(object):
"""用於測試socket請求"""
def __init__(self, domain, port, timeout=30, max_receive=102400):
self.domain = domain
self.port = port
self.connected = 0 # 連接後置爲1
self.max_receive = max_receive
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.settimeout(timeout)
def connect(self):
"""連接指定IP、端口"""
if not self.connected:
try:
self._sock.connect((self.domain, self.port))
except socket.error as e:
logger.exception(e)
else:
self.connected = 1
logger.debug('TCPClient connect to {0}:{1} success.'.format(self.domain, self.port))
def send(self, data, dtype='str', suffix=''):
"""向服務器端發送send_string,並返回信息,若報錯,則返回None"""
if dtype == 'json':
send_string = json.dumps(data) + suffix
else:
send_string = data + suffix
self.connect()
if self.connected:
try:
self._sock.send(send_string.encode())
logger.debug('TCPClient Send {0}'.format(send_string))
except socket.error as e:
logger.exception(e)
try:
rec = self._sock.recv(self.max_receive).decode()
if suffix:
rec = rec[:-len(suffix)]
logger.debug('TCPClient received {0}'.format(rec))
return rec
except socket.error as e:
logger.exception(e)
def close(self):
"""關閉連接"""
if self.connected:
self._sock.close()
logger.debug('TCPClient closed.')
然後在config.yml中添加socket的接口的基本配置:
ip: 127.0.0.1
port: 8080
然後在interface中創建我們的測試test_socket.py
import unittest
from utils.client import TCPClient
from utils.config import Config
from utils.extractor import JMESPathExtractor
je = JMESPathExtractor()
class TestAdd(unittest.TestCase):
def setUp(self):
c = Config()
ip = c.get('ip')
port = c.get('port')
self.client = TCPClient(ip, port)
def tearDown(self):
self.client.close()
def test_add(self):
data = {
'action': 'add',
'params': {'a': 1, 'b': 2}
}
res = self.client.send(data, dtype='json')
self.assertEqual(je.extract('result', res), 3)
self.assertEqual(je.extract('action', res), 'add')
def test_wrong_action(self):
data = {
'action': 'sub',
'params': {'a': 1, 'b': 2}
}
res = self.client.send(data, dtype='json')
self.assertEqual(je.extract('code', res), -2)
self.assertEqual(je.extract('message', res), 'Wrong Action')
def test_wrong_data(self):
data = 'xxxxx'
res = self.client.send(data)
self.assertEqual(je.extract('code', res), -1)
self.assertEqual(je.extract('message', res), 'Data Error')
if __name__ == '__main__':
unittest.main(verbosity=2)
簡單的測試用例完成了,執行下(先把mock server跑起來喲):
test_add (__main__.TestAdd) ... ok
test_wrong_action (__main__.TestAdd) ... ok
test_wrong_data (__main__.TestAdd) ... ok
----------------------------------------------------------------------
Ran 3 tests in 0.009s
OK
當然,接口不可能這麼簡單,用例也不可能就這幾個,這裏只是簡單舉個栗子,會應用了,再複雜的socket接口都是一個樣子。
這裏我們用了自己mock的server,當開發真正的接口通了之後,改改config.yml中的ip和port,就可以直接執行測試了。