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

Fre*_*oth 19 python mocking

我尝试用mockpython编写一些单元测试.

例如,我有以下课程:

class TCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        self.data = self.request.recv(1024).strip()
Run Code Online (Sandbox Code Playgroud)

我只想测试这个handle方法.无需担心任何事情socketserver.BaseRequestHandler.例如,我想断言用参数handle调用.是否有可能用模拟做这样的事情?即用模拟替换基类?或者我是否偏离了这个想法?recv1024socketserver.BaseRequestHandler


有了ecatmur的答案(谢谢!)我首先尝试了以下内容:

patcher = patch.object(TCPHandler, '__bases__', (Mock,))
with patcher:
    patcher.is_local = True
    handler = TCPHandler()
    handler.handle()
Run Code Online (Sandbox Code Playgroud)

但现在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']
Run Code Online (Sandbox Code Playgroud)

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

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


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

mock = MagicMock()
TCPHandler.handle(mock)
#assertions
Run Code Online (Sandbox Code Playgroud)

然而,模拟似乎没有被称为.

eca*_*mur 21

您可以通过修补派生类来执行此操作__bases__:

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

is_local黑客是必须停止mock.patch从试图调用delattr倒车修补程序时.


Pig*_*ras 6

我不知道它是否是最好的解决方案但是我使用type()管理了使用不同父级重新定义上一个类.我构建了一个名为的函数patch_parent(),它返回带有父模拟的类:

from contextlib import contextmanager

@contextmanager
def patch_parent(class_):
    """
    Mock the bases
    """
    yield type(class_.__name__, (Mock,), dict(class_.__dict__))
Run Code Online (Sandbox Code Playgroud)

在此之后,你可以使用patch_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)
Run Code Online (Sandbox Code Playgroud)

MockFoo类仍然有方法Foo的类,它没有父定义的方法,因为父母现在是一个 Mock类.


ayc*_*dee 5

我认为问题实际上是你试图模拟你想要测试的实际代码.而不是该代码调用的对象.如果你有兴趣看看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)
Run Code Online (Sandbox Code Playgroud)

你可能需要做一些额外的设置才能让处理程序实例化,但基本的想法应该是清楚的.