測試socket接口

測試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,就可以直接執行測試了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章