我正在开发一个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)
我环顾四周,发现了一些类似的问题和答案,例如:使用预期的Mock
或设置data, addr
通过其构造函数初始化side_effect
(我已尝试过这个),但我无法通过我的测试成功运行。
如何设置已修补的socket
模块,以便在测试条件下从data, addr
获取预期的配对s.recvfrom(...)
?
答案 0 :(得分:2)
此处的问题是您在socket
中模拟upnp.mucassdp
模块导入,然后尝试使用recvfrom()
调用进行配置。但是,recvfrom()
类上存在socket.socket
方法,而不是socket
模块。
@patch('upnp.mucassdp.socket')
def test_msearch(self, mock_socket):
# mock_socket is the module, not the socket class
解决方法是修补socket.socket
类,然后在测试中,在配置之前检索实例。
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)