2012-08-29 40 views
84

我正在使用模拟库来测试我的应用程序,但我想断言某些函数未被调用。模拟文档谈论像mock.assert_called_withmock.assert_called_once_with方法,但我没有找到像mock.assert_not_called或验证模拟相关的东西被不叫什么。断言函数/方法没有使用模拟调用

我可以像下面去了,但它似乎并不冷静,也不符合Python:

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

由于@Ahmet在他的回答中指出,现在assert_not_called支持,也是在反向移植(https://docs.python.org/3/library/unittest.mock.html#unittest.mock .Mock.assert_not_called)。 – Martin

回答

106

这应该适合您的情况;

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

这个答案需要Django吗?我得到一个错误:'AttributeError:MockCallable实例没有属性''' –

+0

@NathanArthur嗯,我不这么认为,在'sudo easy_install -U mock'和'从模拟导入Mock'到MacOS之后,以上运行顺利。从来没有安装Django :) –

+0

嗯。这很奇怪。我正在运行Python 2.7.1,并使用unittest和'from mock import Mock'和Python Mock 0.1.0来进行测试。有没有听起来有问题? –

25

您可以检查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) 
11

当您测试使用类继承unittest.TestCase生成可以只需使用类似的方法:

  • assertTrue
  • assertFalse
  • assertEqual便

和相似(在python documentation你找到的其余部分)。

在您的例子,我们可以简单地断言,如果mock_method.called属性为,这意味着法不叫。

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

从其他的答案来看,任何人,除非@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,并测试它是否被调用了某个值,但不是其他值。

26

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

只是升级你的;

pip install mock --upgrade

相关问题