在Python单元测试中断言某方法被调用
假设我在一个Python单元测试中有以下代码:
aw = aps.Request("nv1")
aw2 = aps.Request("nv2", aw)
有没有简单的方法可以检查在测试的第二行中,某个特定的方法(在我的例子中是 aw.Clear()
)是否被调用了?比如说,有没有类似这样的东西:
#pseudocode:
assertMethodIsCalled(aw.Clear, lambda: aps.Request("nv2", aw))
5 个回答
14
我不知道有没有现成的功能可以用。不过实现起来其实很简单:
class assertMethodIsCalled(object):
def __init__(self, obj, method):
self.obj = obj
self.method = method
def called(self, *args, **kwargs):
self.method_called = True
self.orig_method(*args, **kwargs)
def __enter__(self):
self.orig_method = getattr(self.obj, self.method)
setattr(self.obj, self.method, self.called)
self.method_called = False
def __exit__(self, exc_type, exc_value, traceback):
assert getattr(self.obj, self.method) == self.called,
"method %s was modified during assertMethodIsCalled" % self.method
setattr(self.obj, self.method, self.orig_method)
# If an exception was thrown within the block, we've already failed.
if traceback is None:
assert self.method_called,
"method %s of %s was not called" % (self.method, self.obj)
class test(object):
def a(self):
print "test"
def b(self):
self.a()
obj = test()
with assertMethodIsCalled(obj, "a"):
obj.b()
这段代码需要确保对象本身不会修改 self.b,通常来说这是几乎总是成立的。
36
如果你使用的是Python 3.3或更高版本,那就没问题。你可以用内置的unittest.mock
来检查某个方法是否被调用。如果你用的是Python 2.6或更高版本,可以使用一个叫做Mock
的库,它的功能和前面提到的差不多。
下面是一个简单的例子,适合你的情况:
from unittest.mock import MagicMock
aw = aps.Request("nv1")
aw.Clear = MagicMock()
aw2 = aps.Request("nv2", aw)
assert aw.Clear.called
211
我使用的是Mock(在Python 3.3及以上版本中叫做unittest.mock)来做这个:
from mock import patch
from PyQt4 import Qt
@patch.object(Qt.QMessageBox, 'aboutQt')
def testShowAboutQt(self, mock):
self.win.actionAboutQt.trigger()
self.assertTrue(mock.called)
对于你的情况,它可能看起来像这样:
import mock
from mock import patch
def testClearWasCalled(self):
aw = aps.Request("nv1")
with patch.object(aw, 'Clear') as mock:
aw2 = aps.Request("nv2", aw)
mock.assert_called_with(42) # or mock.assert_called_once_with(42)
Mock有很多实用的功能,包括可以修改一个对象或模块,以及检查是否调用了正确的东西等等。
如果你把assert_called_with
打错了(比如打成assert_called_once
或者把两个字母调换成assert_called_wiht
),你的测试可能还是会运行,因为Mock会认为这是一个被模拟的函数,并且会顺利执行,除非你使用autospec=true
。想了解更多信息,可以阅读assert_called_once: 威胁还是麻烦。