web-dev-qa-db-ja.com

Python 2.7モック/パッチ:assert_called_XYZ()を理解する

私はPythonおよびPythonでのユニットテストに比較的慣れていません。Javaの世界から、モックの概念を知っていますが、何とはかなり異なるようですPythonで見ることができます。

私はこのガイドを見つけましたが、とても役に立ちました: http://www.voidspace.org.uk/python/mock/index.html

しかし、依存関係をモックアウトした私の(もう少し複雑な)テストを書いたとき、私はストレージの動作に気づきました。私は、期待どおりに機能しない、縮小された単純な例を作成することにしました。

これを見て、結果と私がコメントとして追加した私の期待:

_import unittest
from mock import patch, Mock, MagicMock

class BasicTest(unittest.TestCase):

    @patch("StringIO.StringIO")
    def testSomethingNotWorkingAsExpected(self, StringIOMock):
        StringIOMock.assert_called_once() # asserts, but why?

    @patch("StringIO.StringIO")
    def testSomethingSomehowWorking(self, StringIOMock):
        # self.instantiateStringIO() # intentionally commented out
        assert StringIOMock.called # does not assert (leading to failure of this test); as expected. If the above line is not commented, this asserts as expected.

    def instantiateStringIO(self):
        import StringIO
        StringIO.StringIO()
_

assert_called_once()がまだインスタンス化されていないのに、StringIOのインスタンス化をアサートするのはなぜですか?そして、なぜ_assert ClassMock.called_が期待される結果をもたらすのですか?

_assert not ..._を使用してメソッドをアサートすることが呼び出されていない: 関数/メソッドがMock を使用して呼び出されていない私の場合、notを省略してこのパターンを反転させました。

どこかで、インスタンスを参照するパターン_ClassMock.return_value_を見つけました。しかし、これは、モックのインスタンスが呼び出される前に操作する方法として理解しているのであり、基になるコードが内部で作成した可能性のあるインスタンスにアクセスする方法としては理解していません。それとも私は間違っていますか?

私の環境:

  • Python 2.7.3
  • モック0.8.8
  • Fedora 19

おそらく、モック/パッチについての私の理解は間違っています。クラスのモックの機能とその仕組みを誰かが追加で説明してくれませんか?

Edit1:追加された出力

... testSomethingSomehowWorkingでコメントするために括弧で言い換えを追加

これは出力です:

_.F
======================================================================
FAIL: testSomethingSomehowWorking (test_test.BasicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/mock.py", line 1224, in patched
    return func(*args, **keywargs)
  File "test_test.py", line 15, in testSomethingSomehowWorking
    assert StringIOMock.called # does not assert; as expected
AssertionError

----------------------------------------------------------------------
Ran 2 tests in 0.001s

FAILED (failures=1)
_
16

メソッド_assert_called_once_は存在せず、アサーションを実行しません。 StringIOMock.assert_foo_bar_does_not_exist()やその他のメソッドを書くことと何の違いもありません。モックライブラリは、モックで呼び出されたメソッドが実際に存在するかどうかをチェックしません。

_assert_called_once_with_ を使用すると、期待どおりに失敗します。

specパラメータを使用して、存在しないメソッドを呼び出すときにエラーを発生させることができます。

_@patch("StringIO.StringIO", spec=StringIO.StringIO)
def testSomethingNotWorkingAsExpected(self, StringIOMock):
    StringIOMock.assert_called_once() # will fail as the method doesn't exist
_
12
Simeon Visser