簡體   English   中英

使用 Mock 斷言未調用函數/方法

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

我正在使用 Mock 庫來測試我的應用程序,但我想斷言某些函數沒有被調用。 模擬文檔討論了諸如mock.assert_called_withmock.assert_called_once_with類的方法,但我沒有找到類似mock.assert_not_called或與 verify mock mock.assert_not_called 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

任何想法如何實現這一點?

這應該適用於您的情況;

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

雖然是一個老問題,但我想補充一下當前mock庫(unittest.mock 的assert_not_called移植)支持assert_not_called方法。

只需升級您的;

pip install mock --upgrade

您可以檢查被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)

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

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

  • 斷言真
  • 斷言假
  • 斷言相等

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

在您的示例中,我們可以簡單地斷言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))

從其他答案來看,除了@rob-kennedy沒有人談到call_args_list

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

call_args_listcall對象的列表。 每個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 ,並測試它是否已被某些值而不是其他值調用。

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