问题:断言未使用Mock调用函数/方法
我正在使用Mock库来测试我的应用程序,但是我想断言某些函数没有被调用。模拟文档谈论类似的方法mock.assert_called_with
和mock.assert_called_once_with
,但我没有找到像什么mock.assert_not_called
或验证模拟相关的东西是不叫。
我可以使用类似以下的内容,尽管它看起来既不酷也不是pythonic:
def test_something:
# some actions
with patch('something') as my_var:
try:
# args are not important. func should never be called in this test
my_var.assert_called_with(some, args)
except AssertionError:
pass # this error being raised means it's ok
# other stuff
任何想法如何做到这一点?
回答 0
这应该适合您的情况;
assert not my_var.called, 'method should not have been called'
样品;
>>> mock=Mock()
>>> mock.a()
<Mock name='mock.a()' id='4349129872'>
>>> assert not mock.b.called, 'b was called and should not have been'
>>> assert not mock.a.called, 'a was called and should not have been'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AssertionError: a was called and should not have been
回答 1
尽管是一个老问题,我想补充一下当前的mock
库(unittest.mock的反向端口)支持assert_not_called
方法。
只需升级您的;
pip install mock --upgrade
回答 2
您可以检查该called
属性,但是如果断言失败,那么您接下来要了解的是有关意外调用的信息,因此您也可以安排从头开始显示该信息。使用unittest
,您可以查看的内容call_args_list
:
self.assertItemsEqual(my_var.call_args_list, [])
当失败时,它会给出如下消息:
AssertionError:元素计数不相等: 第一个具有0,第二个具有1:call('first arguments',4)
回答 3
当您使用类进行测试时,继承了unittest.TestCase,您可以简单地使用以下方法:
- assertTrue
- 断言错误
- 断言等于
和类似的(在python文档中找到其余的)。
在您的示例中,我们可以简单地断言嘲笑嘲笑的方法是否为False,这意味着未调用该方法。
import unittest
from unittest import mock
import my_module
class A(unittest.TestCase):
def setUp(self):
self.message = "Method should not be called. Called {times} times!"
@mock.patch("my_module.method_to_mock")
def test(self, mock_method):
my_module.method_to_mock()
self.assertFalse(mock_method.called,
self.message.format(times=mock_method.call_count))
回答 4
随便python >= 3.5
可以使用mock_object.assert_not_called()
。
回答 5
从其他答案来看,除了@ rob-kennedy之外,没有人谈论过call_args_list
。
它是一个强大的工具,可以实现与 MagicMock.assert_called_with()
call_args_list
是call
对象列表。每个call
对象代表对模拟可调用对象的调用。
>>> from unittest.mock import MagicMock
>>> m = MagicMock()
>>> m.call_args_list
[]
>>> m(42)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42)]
>>> m(42, 30)
<MagicMock name='mock()' id='139675158423872'>
>>> m.call_args_list
[call(42), call(42, 30)]
使用call
对象很容易,因为您可以将其与长度为2的元组进行比较,其中第一个组件是包含相关调用的所有位置参数的元组,而第二个组件是关键字arguments的字典。
>>> ((42,),) in m.call_args_list
True
>>> m(42, foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((42,), {'foo': 'bar'}) in m.call_args_list
True
>>> m(foo='bar')
<MagicMock name='mock()' id='139675158423872'>
>>> ((), {'foo': 'bar'}) in m.call_args_list
True
因此,解决OP特定问题的一种方法是
def test_something():
with patch('something') as my_var:
assert ((some, args),) not in my_var.call_args_list
请注意,通过这种方式,MagicMock.called
您不仅可以通过检查是否已调用了模拟的可调用对象,还可以通过一组特定的参数来检查它是否已被调用。
这很有用。假设您要测试一个接受列表的函数,然后compute()
仅在满足特定条件的情况下针对列表的每个值调用另一个函数。
现在compute
,您可以模拟,并测试是否已按某个值调用了它,但未按其他值调用了它。