2012-08-29 61 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

相關問題