web-dev-qa-db-ja.com

Mockを使用して関数/メソッドが呼び出されなかったとアサートする

Mockライブラリを使用してアプリケーションをテストしていますが、一部の関数が呼び出されなかったことをアサートしたいです。モックのドキュメントでは、mock.assert_called_withmock.assert_called_once_withなどのメソッドについて説明していますが、mock.assert_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

これを達成する方法はありますか?

助けてくれてありがとう:)

112
Gerard

これはあなたのケースで機能するはずです。

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
128

古い質問ですが、現在mockライブラリ(unittest.mockのバックポート)がassert_not_calledメソッドをサポートしていることを追加したいと思います。

アップグレードしてください。

pip install mock --upgrade

49
Ahmet

called属性を確認できますが、アサーションが失敗した場合、次に知りたいことは何かabout予期しない呼び出しです。そのため、その情報を最初から表示されます。 unittestを使用すると、代わりにcall_args_listの内容を確認できます。

self.assertItemsEqual(my_var.call_args_list, [])

失敗すると、次のようなメッセージが表示されます。

 AssertionError:要素数が等しくありませんでした:
最初の要素は0、2番目の要素は1:call( 'first argument'、4)
28
Rob Kennedy

クラス継承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))
12
Hunter_71

python >= 3.5を使用すると、mock_object.assert_not_called()を使用できます。

3
valex

他の回答から判断すると、 @ rob-kennedy 以外の誰もcall_args_listについて話していません。

MagicMock.assert_called_with()の正反対を実装できる強力なツールです

call_args_listcallオブジェクトのリストです。各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番目のコンポーネントがキーワード引数の辞書である長さ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

この方法では、モックされたcallableがMagicMock.calledを介して呼び出されたかどうかを確認する代わりに、特定の引数セットで呼び出されたかどうかを確認できることに注意してください。

それは便利です。リストを取得し、特定の条件を満たす場合にのみ、リストの各値に対して別の関数compute()を呼び出す関数をテストするとします。

これでcomputeをモックでき、ある値で呼び出されたが、他の値では呼び出されなかったかどうかをテストできます。

1
Giuseppe Crinò