I am working on a multicast project with python3 and have a small program to search for upnp devices on the local network. I want to use unittest and mock the expensive call to socket.recvfrom(bufsize[, flags]).
Here is my program ./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
And here is my test case ./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)
When I try to run the test case with:
~$ python3 -m unittest tests.mucassdpTest
I get the error message (only relevant part):
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)
I've looked around and found some similar questions and answers, e.g. initialize Mock through its constructor with the expected data, addr or setup side_effect ( I've tried this) but I cannot get it to run successfully with my test.
How do I have to set up the patched socket module to get the expected paired data, addr from s.recvfrom(...) under test conditions?