Python 3.x 如何在python中模拟套接字模块?

Python 3.x 如何在python中模拟套接字模块?,python-3.x,mocking,raspbian,python-unittest,Python 3.x,Mocking,Raspbian,Python Unittest,我正在使用python3进行一个多播项目,并有一个小程序在本地网络上搜索upnp设备。我想使用unittest和mock对socket.recvfrom(bufsize[,flags])的昂贵调用 这是我的程序/upnp/mucassdp.py: #!/usr/bin/env python3 import socket class ssdpObj(): # Handle Simple Service Discovery Protocol, # for discovering UPnP dev

我正在使用
python3
进行一个多播项目,并有一个小程序在本地网络上搜索
upnp
设备。我想使用
unittest
mock
socket.recvfrom(bufsize[,flags])
的昂贵调用

这是我的程序
/upnp/mucassdp.py

#!/usr/bin/env python3

import socket

class ssdpObj():
# Handle Simple Service Discovery Protocol,
# for discovering UPnP devices on the local network

    def msearch(self):
        msg = \
            'M-SEARCH * HTTP/1.1\r\n' \
            'HOST:239.255.255.250:1900\r\n' \
            'ST:upnp:rootdevice\r\n' \
            'MX:2\r\n' \
            'MAN:"ssdp:discover"\r\n' \
            '\r\n'

        # Set up UDP socket with timeout and send a M-SEARCH structure
        # to the upnp multicast address and port
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        s.settimeout(2)
        s.sendto(msg.encode(), ('239.255.255.250', 1900) )

        # print received data within the timeout
        try:
            while True:
                # expensive call to mock for testing
                data, addr = s.recvfrom(65507)

                print (addr, data.decode(), end='')
        except socket.timeout:
            pass
#!/usr/bin/env python3

import unittest
from unittest.mock import patch

from upnp.mucassdp import ssdpObj


class mucassdpTestCase(unittest.TestCase):

    @patch('upnp.mucassdp.socket')
    def test_msearch(self, mock_socket):
        # instantiate our service
        oSsdp = ssdpObj()

        mock_socket.recvfrom.return_value = [0, '1']
        #mock_socket.recvfrom.side_effect = [0, '1']

        oSsdp.msearch()
        mock_socket.settimeout.assert_called_with(2)
这是我的测试用例
/tests/mucassdpTest.py

#!/usr/bin/env python3

import socket

class ssdpObj():
# Handle Simple Service Discovery Protocol,
# for discovering UPnP devices on the local network

    def msearch(self):
        msg = \
            'M-SEARCH * HTTP/1.1\r\n' \
            'HOST:239.255.255.250:1900\r\n' \
            'ST:upnp:rootdevice\r\n' \
            'MX:2\r\n' \
            'MAN:"ssdp:discover"\r\n' \
            '\r\n'

        # Set up UDP socket with timeout and send a M-SEARCH structure
        # to the upnp multicast address and port
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
        s.settimeout(2)
        s.sendto(msg.encode(), ('239.255.255.250', 1900) )

        # print received data within the timeout
        try:
            while True:
                # expensive call to mock for testing
                data, addr = s.recvfrom(65507)

                print (addr, data.decode(), end='')
        except socket.timeout:
            pass
#!/usr/bin/env python3

import unittest
from unittest.mock import patch

from upnp.mucassdp import ssdpObj


class mucassdpTestCase(unittest.TestCase):

    @patch('upnp.mucassdp.socket')
    def test_msearch(self, mock_socket):
        # instantiate our service
        oSsdp = ssdpObj()

        mock_socket.recvfrom.return_value = [0, '1']
        #mock_socket.recvfrom.side_effect = [0, '1']

        oSsdp.msearch()
        mock_socket.settimeout.assert_called_with(2)
当我尝试使用以下内容运行测试用例时:

~$ python3 -m unittest tests.mucassdpTest
我收到错误消息(仅相关部分):

我环顾四周,发现了一些类似的问题和答案,例如,使用预期的
数据通过构造函数初始化
Mock
,添加
或设置
副作用(我已经尝试过了),但我无法让它在测试中成功运行


在测试条件下,如何设置打补丁的
套接字
模块,以从
s.recvfrom(…)
获取预期的成对
数据,addr

这里的问题是,您在
upnp.mucassdp
中模拟
套接字
模块导入,然后尝试用
recvfrom()配置它
打电话。但是,
recvfrom()
方法存在于
socket.socket
类中,而不是
socket
模块中

@patch('upnp.mucassdp.socket')
def测试搜索(自模拟插座):
#mock_socket是模块,而不是socket类
解决方法是修补
socket.socket
类,然后在测试中,在配置实例之前检索实例

类mucassdpTestCase(unittest.TestCase):
@修补程序('upnp.mucassdp.socket.socket')#修补该类
def测试搜索(自模拟插座):
mock_socket=mock_socket.return_value#我们需要实例
#实例化我们的服务
oSsdp=ssdpObj()
mock_socket.recvfrom.return_value=[0,'1']
#mock_socket.recvfrom.side_effect=[0,'1']
oSsdp.msearch()
mock_socket.settimeout.assert_调用了(2)