简体   繁体   English

使用 Mock 断言未调用函数/方法

[英]Assert a function/method was not called using Mock

I'm using the Mock library to test my application, but I want to assert that some function was not called.我正在使用 Mock 库来测试我的应用程序,但我想断言某些函数没有被调用。 Mock docs talk about methods like mock.assert_called_with and mock.assert_called_once_with , but I didn't find anything like mock.assert_not_called or something related to verify mock was NOT called .模拟文档讨论了诸如mock.assert_called_withmock.assert_called_once_with类的方法,但我没有找到类似mock.assert_not_called或与 verify mock mock.assert_not_called NOT called相关的东西。

I could go with something like the following, though it doesn't seem cool nor pythonic:我可以使用以下内容,尽管它看起来既不酷也不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

Any ideas how to accomplish this?任何想法如何实现这一点?

This should work for your case;这应该适用于您的情况;

assert not my_var.called, 'method should not have been called'

Sample;样本;

>>> 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

Though an old question, I would like to add that currently mock library (backport of unittest.mock) supports assert_not_called method.虽然是一个老问题,但我想补充一下当前mock库(unittest.mock 的assert_not_called移植)支持assert_not_called方法。

Just upgrade yours;只需升级您的;

pip install mock --upgrade

You can check the called attribute, but if your assertion fails, the next thing you'll want to know is something about the unexpected call, so you may as well arrange for that information to be displayed from the start.您可以检查被called属性,但是如果您的断言失败,那么您接下来想知道的是有关意外调用的信息,因此您最好从一开始就安排显示该信息。 Using unittest , you can check the contents of call_args_list instead:使用unittest ,您可以检查call_args_list的内容:

self.assertItemsEqual(my_var.call_args_list, [])

When it fails, it gives a message like this:当它失败时,它会给出如下消息:

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

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

When you test using class inherits unittest.TestCase you can simply use methods like:当您使用类继承unittest.TestCase 进行测试时,您可以简单地使用以下方法:

  • assertTrue断言真
  • assertFalse断言假
  • assertEqual断言相等

and similar (in python documentation you find the rest).和类似的(在python 文档中你可以找到其余的)。

In your example we can simply assert if mock_method.called property is False , which means that method was not called.在您的示例中,我们可以简单地断言mock_method.call属性是否为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))

Judging from other answers, no one except @rob-kennedy talked about the call_args_list .从其他答案来看,除了@rob-kennedy没有人谈到call_args_list

It's a powerful tool for that you can implement the exact contrary of MagicMock.assert_called_with()这是一个强大的工具,您可以实现与MagicMock.assert_called_with()完全相反的MagicMock.assert_called_with()

call_args_list is a list of call objects. call_args_listcall对象的列表。 Each call object represents a call made on a mocked callable.每个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)]

Consuming a call object is easy, since you can compare it with a tuple of length 2 where the first component is a tuple containing all the positional arguments of the related call, while the second component is a dictionary of the keyword arguments.使用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

So, a way to address the specific problem of the OP is因此,解决 OP 特定问题的一种方法是

def test_something():
    with patch('something') as my_var:
        assert ((some, args),) not in my_var.call_args_list

Note that this way, instead of just checking if a mocked callable has been called, via MagicMock.called , you can now check if it has been called with a specific set of arguments.请注意,通过这种方式,您现在可以检查是否已使用一组特定的参数调用它,而不仅仅是检查是否已调用MagicMock.called可调用对象。

That's useful.这很有用。 Say you want to test a function that takes a list and call another function, compute() , for each of the value of the list only if they satisfy a specific condition.假设您要测试一个函数,该函数接受一个列表并仅在满足特定条件时才为列表的每个值调用另一个函数compute()

You can now mock compute , and test if it has been called on some value but not on others.您现在可以模拟compute ,并测试它是否已被某些值而不是其他值调用。

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

my_var.assert_not_called()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM