断言没有使用Mock调用函数/方法

时间:2012-08-29 21:59:50

标签: python unit-testing mocking python-mock

我正在使用Mock库来测试我的应用程序,但我想断言某些函数没有被调用。模拟文档讨论mock.assert_called_withmock.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

任何想法如何实现这一目标?

感谢您的帮助:)

6 个答案:

答案 0 :(得分:122)

这适用于您的情况;

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 :(得分:45)

虽然这是一个老问题,但我想补充一点,目前mock库(unittest.mock的backport)支持assert_not_called方法。

升级你的;

pip install mock --upgrade

答案 2 :(得分:28)

你可以查看called属性,但如果你的断言失败了,那么你想知道的下一件事就是关于意外的电话,所以你也可以安排一下从一开始就要显示的信息。使用unittest,您可以检查call_args_list的内容:

self.assertItemsEqual(my_var.call_args_list, [])

当它失败时,会发出如下信息:

AssertionError: Element counts were not equal:
First has 0, Second has 1:  call('first argument', 4)

答案 3 :(得分:11)

当您使用类继承 unittest.TestCase 进行测试时,您可以使用以下方法:

  • assertTrue
  • assertFalse
  • assertEqual便

和类似的(在python documentation中找到其余部分)。

在您的示例中,我们可以简单断言 mock_method.called 属性 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 :(得分:1)

从其他答案来看,除了@rob-kennedy之外,没有人谈到call_args_list

它是一个强大的工具,您可以实现与MagicMock.assert_called_with()完全相反的

call_args_listcall个对象的列表。每个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的元组进行比较,其中第一个组件是包含相关调用的所有位置参数的元组,而第二个组件是一个字典关键字参数。

>>> ((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,并测试是否已经调用某个值而不是其他值。

答案 5 :(得分:1)

通过python >= 3.5,您可以使用mock_object.assert_not_called()