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

如何使用python模拟库模拟基类,python,mocking,Python,Mocking,我尝试使用mock用python编写一些单元测试 例如,我有以下课程: class TCPHandler(socketserver.BaseRequestHandler): def handle(self): self.data = self.request.recv(1024).strip() 我只想测试句柄方法。无需假设任何关于socketserver.BaseRequestHandler的信息。例如,我想断言handle使用参数1024调用recv。有可能用moc

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

例如,我有以下课程:

class TCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
我只想测试
句柄
方法。无需假设任何关于
socketserver.BaseRequestHandler
的信息。例如,我想断言
handle
使用参数
1024
调用
recv
。有可能用mock做这样的事情吗?也就是说,将基类
socketserver.BaseRequestHandler
替换为模拟?还是我的想法偏离了轨道


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

patcher = patch.object(TCPHandler, '__bases__', (Mock,))
with patcher:
    patcher.is_local = True
    handler = TCPHandler()
    handler.handle()
但是现在不再调用
handle
,并且
dir(handler)
给出:

['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']
类型(处理程序)
给出

我的解释是,修补基类也会将派生类变成模拟类


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

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

但是,似乎没有调用mock。

您可以通过修补派生类的
\uuuuuuu基来完成此操作:

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

是本地的
黑客是阻止
mock.patch
尝试调用
delattr
的必要手段。我认为问题确实在于您试图模拟要测试的实际代码。而不是由该代码调用的对象。如果您对handle方法是否在self.request上调用recv方法感兴趣,那么可以模拟recv方法

def test_tcp_handler_method(self):

    handler = TCPHandler()
    handler.request = Mock()

    handler.handle()

    self.assertTrue(handler.request.recv.called)
    self.assertEqual(handler.request.recv.call_args[0], 1024)

为了让处理程序实例化,您可能需要进行一些额外的设置,但基本思想应该很清楚

我不知道这是否是最好的解决方案,但我设法使用不同的父类重新定义了上一个类。我构建了一个名为
patch\u parent()
的函数,该函数返回带有父模拟的类:

from contextlib import contextmanager

@contextmanager
def patch_parent(class_):
    """
    Mock the bases
    """
    yield type(class_.__name__, (Mock,), dict(class_.__dict__))
在此之后,您可以像这样使用
patch\u parent

class Bar():
   def method(self, param1, param2...):
       ...

class Foo(Bar):
   pass


>>> with patch_parent(Foo) as MockFoo:
...     f = MockFoo()
...     print f
...     print f.method()
... 
<Foo id='15488016'>
<Foo name='mock.method()' id='15541520'>
>>> s = Foo()
>>> s.method()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: method() takes exactly 3 arguments (1 given)
class Bar():
def方法(self、param1、param2…):
...
级别Foo(Bar):
通过
>>>将补丁_父对象(Foo)作为MockFoo:
...     f=MockFoo()
...     打印f
...     打印f.方法()
... 
>>>s=Foo()
>>>s.方法()
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
TypeError:method()正好接受3个参数(给定1个)

MockFoo
类仍然具有
Foo
类的方法,并且没有在父类中定义的方法,因为父类现在是一个
Mock
类。

我遵循了您的提示,但结果是,派生类的方法也被mock替换了。我把我当前的测试代码放在了问题中,你可以看一下吗?我感谢你的帮助。@FrederickRoth不太确定;对于我来说,使用Python 2很好。也许可以试着模拟方法访问的对象部分?我用python 2.7而不是python 3测试了你的想法,现在我得到一个类型错误:TypeError:base项必须是类。好的,谢谢!我认为您的解决方案很好,但不幸的是,我无法在我的环境中真正使用它。谢谢您的输入!TCPHandler需要一个tcprequest来实例化,因此它从不直接由我的代码实例化,而是由TCPServer实例化。这就是我不想调用它的
\uuuuu init\uuuuu
的全部原因。我只想测试我自己的小方法,而不必测试整个tcpserver框架。对于任何第一次看到google结果的人来说:我只是在智能卡阅读器上遇到了同样的问题。我发现robru是一个功能解决方案。