Python 如何通过模拟库模拟套接字对象

Python 如何通过模拟库模拟套接字对象,python,unit-testing,mocking,Python,Unit Testing,Mocking,如何通过库模拟Python标准库中的TCPSocket套接字包装器(unittest.mock,对于Python 3) 这是我的包装纸: import socket import utils class TCPSocket: def __init__(self): self.buf = '' def __enter__(self): pass def __exit__(self, exc_type, exc_val, exc_tb

如何通过库模拟Python标准库中的
TCPSocket
套接字包装器(
unittest.mock,对于Python 3)

这是我的包装纸:

import socket

import utils


class TCPSocket:
    def __init__(self):
        self.buf = ''

    def __enter__(self):
        pass

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def connect(self, host, port):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.connect((host, port))

    def close(self):
        self.sock.close()

    def send(self, data):
        self.sock.send(data)

    def sendall(self, data):
        self.sock.sendall(data)

    # For best match with hardware and network realities,
    # the value of limit should be a relatively small power of 2, for example, 4096
    def recv_some(self, limit=4096):
        return self.sock.recv(limit)

    def recv_bytes(self, count):
        while len(self.buf) < count:
            self.buf += self.recv_some()
        parts = utils.split_first_n(self.buf, count)
        self.buf = parts[1]
        return parts[0]

    def recv_until(self, delim):
        while delim not in self.buf:
            self.buf += self.recv_some()
        parts = self.buf.split(delim, maxsplit=1)
        self.buf = parts[1]
        return parts[0]
导入套接字
导入UTIL
TCPSocket类:
定义初始化(自):
self.buf=“”
定义输入(自我):
通过
定义退出(自身、exc类型、exc val、exc tb):
self.close()
def连接(自身、主机、端口):
self.sock=socket.socket(socket.AF\u INET,socket.sock\u STREAM)
self.sock.connect((主机、端口))
def关闭(自我):
self.sock.close()
def发送(自身、数据):
self.sock.send(数据)
def sendall(自身、数据):
self.sock.sendall(数据)
#为了与硬件和网络现实最佳匹配,
#limit的值应该是相对较小的2次方,例如4096
def recv_部分(自限=4096):
返回self.sock.recv(限制)
def recv_字节(自身,计数):
而len(self.buf)<计数:
self.buf+=self.recv_some()
parts=utils.split\u first\n(self.buf,count)
self.buf=零件[1]
退货零件[0]
def recv_直到(自身,delim):
delim不在self.buf中时:
self.buf+=self.recv_some()
零件=自分割(delim,maxsplit=1)
self.buf=零件[1]
退货零件[0]
我想测试像recv_until和recv_bytes这样的函数是否能满足它们的实际需要

import mock   # or from unittest import mock


mock_socket = mock.Mock()
mock_socket.recv.return_value = data
然后使用
mock_socket
,您将使用真正的socket。您还可以模拟创建套接字的任何内容,以返回类似于此处配置的模拟值,具体取决于您的需要


对于您的情况,您可以模拟socket.socket,以便它返回您可以配置其方法的内容。请注意,本例中的
mock_socket
是一个返回
socket
对象的函数,而不是
socket
对象本身

with mock.patch('socket.socket') as mock_socket:
    mock_socket.return_value.recv.return_value = some_data
    t = TCPSocket()
    t.connect('example.com', 12345)  # t.sock is a mock object, not a Socket
self.assertEqual(t.recv_bytes(), whatever_you_expect)
t.sock.connect.assert_called_with(('example.com', 12345))

我不完全理解如何使用这个模拟对象。我有一个来自Python标准库的
socket
包装器,名为
TCPSocket
,方法是
connect
recv\u some
。那我该怎么办?您真的需要模拟
socket
,还是需要模拟
TCPSocket
实例?请用您需要的确切场景编辑您的问题:使用模拟对象、输入和预期输出的代码。我想测试像
recv_until
recv_bytes
这样的函数是否做了它们真正需要的事情。在这种情况下,它会因为未初始化的
self.sock
实例而抱怨。因此,我似乎需要调用应该以某种方式进行修补的
connect
函数
connect
函数在这种情况下如何工作?即使在指定的(IP_ADDR,端口)上没有侦听器,它也不会抱怨地址无效