python mock教學 - 斷言一個函數/方法不是使用Mock調用的




unittest教學 pytest教學 (5)

雖然是一個老問題,但我想補充一點,目前mock庫( assert_not_called backport)支持assert_not_called方法。

只是升級你的;

pip install mock --upgrade

我正在使用模擬庫來測試我的應用程序,但我想斷言某些函數未被調用。 模擬文檔討論像mock.assert_called_withmock.assert_called_once_with這樣的方法,但是我沒有找到類似mock.assert_not_called或者與驗證mock 沒有關聯的東西。

我可以像下面這樣做,儘管它看起來並不酷,也沒有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

任何想法如何做到這一點?

謝謝你的幫助 :)


從其他答案來看,除了@rob-kennedy之外沒有人談論過call_args_list

這是一個強大的工具,您可以執行MagicMock.assert_called_with()的完全相反

call_args_list是一個call對象列表。 每個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檢查是否已調用MagicMock.called調用MagicMock.called ,而不是僅僅通過一組特定的參數來檢查它是否已被調用。

這很有用。 假設你想要測試一個帶有列表的函數,並且只有在列表中的每個值滿足特定條件時才調用另一個函數compute()

你現在可以模擬compute ,並測試它是否被調用了一些值,但不是其他值。


這應該適合你的情況;

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

當你使用類繼承unittest.TestCase測試時,你可以簡單地使用如下方法:

  • assertTrue
  • assertFalse
  • assertEqual便

和類似的(在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))

你的模擬正在提升異常,但缺少error.resp.status值。 而不是使用return_value ,只需告訴Mock status是一個屬性:

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')

Mock()其他關鍵字參數在結果對像上設置為屬性。

我把你的foobar定義放在my_tests模塊中,在HttpError類中添加,所以我也可以使用它,然後你的測試可以運行成功:

>>> from my_tests import foo, HttpError
>>> import mock
>>> with mock.patch('my_tests.bar') as barMock:
...     barMock.side_effect = HttpError(mock.Mock(status=404), 'not found')
...     result = my_test.foo()
... 
404 - 
>>> result is None
True

你甚至可以看到print '404 - %s' % error.message line run,但我想你想在那裡使用error.content ; HttpError() ,這是HttpError()從第二個參數設置的屬性。





python unit-testing mocking python-mock