我尝试使用mock
在python中编写一些单元测试。
例如,我有以下课程:
class TCPHandler(socketserver.BaseRequestHandler):
def handle(self):
self.data = self.request.recv(1024).strip()
我只想测试handle
方法。无需假设socketserver.BaseRequestHandler
。例如,我想声明handle
使用参数recv
调用1024
。是否有可能用模拟做这样的事情?即用模拟替换基类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']
type(handler)
给出
<class 'mock.TCPHandler'>
我认为修补基类也会将我的派生类转换为模拟。
我现在尝试了另一个想法:
mock = MagicMock()
TCPHandler.handle(mock)
#assertions
然而,模拟似乎没有被调用。
答案 0 :(得分:19)
您可以通过修补派生类的__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
黑客攻击是必要的,以阻止mock.patch
在撤消修补程序时尝试调用delattr
。
答案 1 :(得分: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)
你可能需要做一些额外的设置才能让处理程序实例化,但基本的想法应该是清楚的。
答案 2 :(得分:5)
我不知道这是否是最佳解决方案,但我使用type()管理了使用不同父级重新定义上一课程。我构建了一个名为patch_parent()
的函数,它返回带有父模拟的类:
from contextlib import contextmanager
@contextmanager
def patch_parent(class_):
"""
Mock the bases
"""
yield type(class_.__name__, (Mock,), dict(class_.__dict__))
在此之后,您可以像这样使用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)
MockFoo
类仍然具有Foo
类的方法,并且它没有在父类中定义的方法,因为父类现在是Mock
类。 / p>