如何在python中模拟套接字模块?

时间:2018-04-05 00:22:23

标签: python-3.x mocking raspbian python-unittest

我正在开发一个python3的多播项目,并有一个小程序来搜索本地网络上的upnp设备。我想使用unittestmocksocket.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(...)

1 个答案:

答案 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)