如何在 python 中模拟套接字模块?
How to mock socket module in python?
我正在使用 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
这是我的测试用例 ./tests/mucassdpTest.py
:
#!/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
我收到错误消息(仅相关部分):
ERROR: test_msearch (tests.mucassdpTest.mucassdpTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/ingo/devel/muca-tools/upnp/mucassdp.py", line 27, in msearch
data, addr = s.recvfrom(65507)
ValueError: not enough values to unpack (expected 2, got 0)
我环顾四周,发现了一些类似的问题和答案,例如使用预期的 data, addr
或设置 side_effect
通过其构造函数初始化 Mock
(我试过这个)但我无法通过我的测试成功地将它设置为 运行。
我必须如何设置修补的 socket
模块才能在测试条件下从 s.recvfrom(...)
获得预期的配对 data, addr
?
这里的问题是您在 upnp.mucassdp
中模拟 socket
模块导入,然后尝试使用 recvfrom()
调用对其进行配置。但是,recvfrom()
方法存在于 socket.socket
class,而不是 socket
模块。
@patch('upnp.mucassdp.socket')
def test_msearch(self, mock_socket):
# mock_socket is the module, not the socket class
解决方法是打补丁socket.socket
class,然后在测试中,获取实例再配置。
class mucassdpTestCase(unittest.TestCase):
@patch('upnp.mucassdp.socket.socket') # Patch the class
def test_msearch(self, mock_socket):
mock_socket = mock_socket.return_value # We want the instance
# 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
进行多播项目,并且有一个小程序可以在本地网络上搜索 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
这是我的测试用例 ./tests/mucassdpTest.py
:
#!/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
我收到错误消息(仅相关部分):
ERROR: test_msearch (tests.mucassdpTest.mucassdpTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/ingo/devel/muca-tools/upnp/mucassdp.py", line 27, in msearch
data, addr = s.recvfrom(65507)
ValueError: not enough values to unpack (expected 2, got 0)
我环顾四周,发现了一些类似的问题和答案,例如使用预期的 data, addr
或设置 side_effect
通过其构造函数初始化 Mock
(我试过这个)但我无法通过我的测试成功地将它设置为 运行。
我必须如何设置修补的 socket
模块才能在测试条件下从 s.recvfrom(...)
获得预期的配对 data, addr
?
这里的问题是您在 upnp.mucassdp
中模拟 socket
模块导入,然后尝试使用 recvfrom()
调用对其进行配置。但是,recvfrom()
方法存在于 socket.socket
class,而不是 socket
模块。
@patch('upnp.mucassdp.socket')
def test_msearch(self, mock_socket):
# mock_socket is the module, not the socket class
解决方法是打补丁socket.socket
class,然后在测试中,获取实例再配置。
class mucassdpTestCase(unittest.TestCase):
@patch('upnp.mucassdp.socket.socket') # Patch the class
def test_msearch(self, mock_socket):
mock_socket = mock_socket.return_value # We want the instance
# 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)