164

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

任何想法如何做到这一点?

4

7 回答 7

173

这应该适用于您的情况;

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
于 2012-08-29T22:12:30.073 回答
93

虽然是一个老问题,但我想补充一下当前mock库(unittest.mock 的反向移植)支持assert_not_called方法。

只需升级你的;

pip install mock --upgrade

于 2017-01-10T12:12:00.227 回答
31

您可以检查该called属性,但如果您的断言失败,接下来您会想知道有关意外调用的信息,因此您不妨从一开始就安排显示该信息。使用unittest,您可以检查以下内容call_args_list

self.assertItemsEqual(my_var.call_args_list, [])

当它失败时,它会给出如下消息:

AssertionError:元素计数不相等:
First 有 0,Second 有 1: call('first argument', 4)
于 2013-07-02T17:48:24.983 回答
31

有了python >= 3.5你就可以使用mock_object.assert_not_called()

于 2018-12-07T13:43:19.270 回答
19

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

  • 断言真
  • 断言假
  • 断言相等

和类似的(在python文档中你可以找到其余的)。

在您的示例中,我们可以简单地断言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))
于 2015-06-24T21:48:17.690 回答
2

从其他答案来看,除了@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 的元组进行比较,其中第一个组件是包含相关调用的所有位置参数的元组,而第二个组件是关键字参数的字典。

>>> ((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,并测试它是否已在某些值上调用,但在其他值上未调用。

于 2016-09-24T16:54:57.103 回答
1

根据 python stdlib 文档,对于python >= 3.5,应该使用 assert_not_call

my_var.assert_not_called()

注意:Python 3.5。9 于 2019 年 11 月 1 日发布,这个问题于 2013 年首次提出。

于 2021-11-08T19:04:05.960 回答