单元测试模拟/覆盖套接字的 sendto

Sco*_*ngs 6 python unit-testing python-unittest python-unittest.mock

[编辑:该问题仅存在于 Python 2.7 中。3.7 可以按预期工作。知道有什么区别以及是否可以使其在 2.7 上工作,由于某些原因我必须使用它]

我想sendto使用 Mock 覆盖套接字的方法。我的第一个方法是这样的:

class TestClass01(TestCase):
    @mock.patch.object(socket.socket, "sendto", new=mock_sendto)
    def test_function1(self):
        ...
Run Code Online (Sandbox Code Playgroud)

然而,这导致了一个异常:

AttributeError:“_socketobject”对象属性“sendto”是只读的。

这种方法对于其他类效果很好,但不适用于套接字。我认为,原因是__init__为所有成员函数调用 setattr,如下所示:

def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None):
    if _sock is None:
        _sock = _realsocket(family, type, proto)
    self._sock = _sock
    for method in _delegate_methods:
        setattr(self, method, getattr(_sock, method))      <<<<<<<<<<<<<
Run Code Online (Sandbox Code Playgroud)

然后,我尝试了另一种方法:

class TestClass01(TestCase):
    @mock.patch("socket.socket")
    def test_function1(self, mock_class):
        s = mock.Mock(socket.socket)
        s.sendto = mock_sendto
        s.close = mock_close

        mock_class.return_value = s

        # ... run my tests here ...

        args, kwargs = mock_class.call_args_list[0]

        # Check arguments passed to sendto
Run Code Online (Sandbox Code Playgroud)

然而,这是可行的,调用参数列表给了我:

((2, 2), {})
Run Code Online (Sandbox Code Playgroud)

对应于构造函数AF_INET=2SOCK_DGRAM=2。没有我的呼唤的痕迹sendto。我的解决方法是使用全局变量,这是我从mock_sendto函数中设置的。但不是很优雅。

我有三个问题:

  1. 我可以解决“只读”问题并获得初步的工作方法吗?
  2. 为什么all_args_list只跟踪构造的调用而不跟踪sendto的调用?
  3. 有比使用全局变量更好的方法吗?

预先感谢您的回答!