如何使用 python 模拟库模拟基类

2022-01-08 00:00:00 python mocking

问题描述

我尝试使用 mock 在 python 中编写一些单元测试.

I try to use mock to write some unit-tests in python.

例如我有以下课程:

class TCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()

我只想测试 handle 方法.无需对 socketserver.BaseRequestHandler 做任何假设.例如,我想断言 handle 使用参数 1024 调用 recv.可以用模拟做这样的事情吗?IE.用模拟替换基类 socketserver.BaseRequestHandler?还是我偏离了这个想法?

And I only want to test the handle method. Without having to assume anything about socketserver.BaseRequestHandler. I for example want to assert that handle calls recv with the argument 1024. Is it possible to do such thing with mock? I.e. replacing the base class socketserver.BaseRequestHandler with a mock? Or am I off track with that idea?

在 ecatmur 的回答下(谢谢!)我首先尝试了以下方法:

With the answer of ecatmur (thank you!) I first tried the following:

patcher = patch.object(TCPHandler, '__bases__', (Mock,))
with patcher:
    patcher.is_local = True
    handler = TCPHandler()
    handler.handle()

但是现在 handle 不再被调用并且 dir(handler) 给出:

But now handle is not called anylonger and dir(handler) gives:

['assert_any_call', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

type(handler) 给出<class 'mock.TCPHandler'>

我解释说,修补基类也会将我的派生类变成一个模拟类.

Which I interpret that patching the base class also turns my derived class into a mock.

我现在尝试了另一个想法:

I now gave another idea a try:

mock = MagicMock()
TCPHandler.handle(mock)
#assertions

但是模拟似乎没有被调用.

However the mock seems not to be called.


解决方案

您可以通过修补派生类的 __bases__ 来做到这一点:

You can do this by patching the derived class's __bases__:

def test_derived():
    patcher = mock.patch.object(Derived, '__bases__', (mock.Mock,))
    with patcher:
        patcher.is_local = True
        d = Derived()
        print d.foo()

is_local hack 是阻止 mock.patch 在反转补丁时尝试调用 delattr 所必需的.

The is_local hack is necessary to stop mock.patch from trying to call delattr when reversing the patch.

相关文章