How to build a test framework from 0_ 11 - socket interface test

Posted by SP8600 on Fri, 24 Sep 2021 13:23:19 +0200

During interface testing, in addition to the common http interface, there is another common one, socket interface. Today, I will explain how to test socket interface with Python's own socket library.

1, socket interface

Socket, also known as socket, can be understood as the address of an application and the key to network communication. We can find a host through IP and an application on the host through the port of the host.

In this way, the communication between two applications can be carried out through socket. The specific implementation is to implement a server that has been listening at one end, and send a request to it at the other end and obtain a response. The server processes different requests and returns them. This is the socket interface.

Let's implement a socket interface and test it.

2, Implement a socket server interface

Create a mock folder under test and create a mock folder in it_ socket_ Server.py file:

# -*- coding: utf-8 -*-

"""
@author: lucas
@Function:
@file: mock_socket_server.py
@time: 2021/9/24 11:26 morning
"""
"""
socket server of mock. 
Two interfaces, add and sub
 receive:
{
    "action": "add",
    "params": {"a": 1, "b": 2}
}
return:
{
    "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()

We implemented a simple socket server with an interface add. The interface document developed for you may be as follows:

Interface type: socket
Interface address: 127.0.0.1
Port: 8080
Interface name: addition
action name: add
Input:

nametypeIs it necessary
aintyes
bintyes

Output reference:

nametypemeaning
resultintresult

Input example:

 {
   "action": "add",
    "params": {"a": 1, "b": 2}
 }

Reference example:

{
    "action": "add",
    "result": 3
}

error code:

codemessage
-1Data Error
-2Wrong Action

After getting the interface document, how should we test it?

3. Test socket interface

First, we need a general client class to encapsulate the general methods of socket interface testing, so as to avoid having to write a pile every time. Add TCPClient in client.py

class TCPClient(object):
    """For testing socket request"""
    def __init__(self, domain, port, timeout=30, max_receive=102400):
        self.domain = domain
        self.port = port
        self.connected = 1  # Set to 1 after connection
        self.max_receive = max_receive
        self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self._sock.settimeout(timeout)

    def connect(self):
        """Connection assignment IP,port"""
        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 to server send_stringļ¼ŒAnd return information. If an error is reported, return 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):
        """Close connection"""
        if self.connected:
            self._sock.close()
            logger.debug('TCPClient closed.')

Then add the basic configuration of socket interface in config.yml:

socket:
  ip: 127.0.0.1
  port: 8080

Then create our test in the interface_ socket.py:

# -*- coding: utf-8 -*-

"""
@author: lucas
@Function:
@file: test_socket.py
@time: 2021/9/24 11:37 morning
"""

from utils.client import TCPClient
import unittest
from utils.config import Config
from utils.extractor import JMESPathExtractor

je = JMESPathExtractor()


class TestAdd(unittest.TestCase):

    def setUp(self):
        socket=Config().get('socket')
        ip = socket.get('ip')
        port = socket.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)

After the simple test case is completed, execute it (remember to run mock_socket_server.py first):

{"action": "add", "params": {"a": 1, "b": 2}}
b'{"action": "add", "params": {"a": 1, "b": 2}}'
{"action": "sub", "params": {"a": 1, "b": 2}}
b'{"action": "sub", "params": {"a": 1, "b": 2}}'
xxxxx
b'xxxxx'


Ran 3 tests in 0.030s

OK

Of course, the interface can't be so simple, and the use cases can't be just these. Here's just a chestnut that can be applied. No matter how complex the socket interface is, it looks the same.

Here, we use our own mock server. When the real interface is developed, we can directly execute the test by changing the ip and port in config.yml.

Topics: Python Selenium