2

mockPythonライブラリを使用して、さまざまなモック オブジェクトへの特定の呼び出しシーケンスをアサートするにはどうすればよいですか?

たとえば、次のように主張します。

  • foo(spam, eggs);の呼び出し それから
  • bar(beans, ham);の呼び出し それから
  • の呼び出しfoo(sausage)

fooとのそれぞれにパッチを適用することができbar、結果として得られるモック オブジェクトはそれぞれ、そのモックの呼び出しに関するアサーションを行うことができます。しかし、そのシーケンスについてアサーションを行うには、呼び出しのシーケンス全体にアクセスする必要があります。

はい、理想的には、結果の状態を検査し、事後にそれについてアサーションを行うだけで済みます。しかし、それは一部のシステムでは実現不可能であり、正しい状態の唯一の有効な説明は、「これらの呼び出しはこの特定の順序で行われた」ということです。

mockさまざまなオブジェクトへの一連の呼び出しにアクセスし、呼び出しが正しい順序で期待どおりであったことをアサートするために、ライブラリのどの機能を使用できますか?

4

2 に答える 2

3

Mock は実際にこのビルトインのようなものを提供します。モックにはしばしば親モックがあります...例

somemock.foo  # parent is somemock

親はモック API で直接公開されませんが、子の呼び出しは親に登録されます。

import mock
m = mock.Mock()
m.a('hello world')
m.b('goodbye world')
m.c('kittens!')
m.a('Howdy')
m.assert_has_calls([
  mock.call.a('hello world'),
  mock.call.b('goodbye world'),
  mock.call.c('kittens!'),
  mock.call.a('Howdy')
])  # passes silently
m.assert_has_calls([
  mock.call.a('hello world'),
  mock.call.b('goodbye world'),
  mock.call.a('Howdy'),
  mock.call.c('kittens!')
]) # Error
# Traceback (most recent call last):
#   File "<stdin>", line 1, in <module>
#   File "/usr/local/lib/python2.7/dist-packages/mock.py", line 863, in assert_has_calls
#     'Actual: %r' % (calls, self.mock_calls)
# AssertionError: Calls not found.
# Expected: [call.a('hello world'), call.b('goodbye world'), call.a('Howdy'), call.c('kittens!')]
# Actual: [call.a('hello world'),
#  call.b('goodbye world'),
#  call.c('kittens!'),
#  call.a('Howdy')]

しかし、「私のモックはすべて同じ親に由来するわけではありません」と言うかもしれません。すべてはまだ失われていません!親を作成し、事後的に親にアタッチできます。

parent_mock = mock.Mock()
parent_mock.attach_mock(foomock, 'foo')
parent_mock.attach_mock(barmock, 'bar')

これで、上で行ったのと同じ種類のアサーションを行うことができます (元のモックの親を保持する必要がない限り...その場合、何を伝えればよいかわかりません...)

于 2014-12-05T00:44:51.547 に答える
0

これを解決するための最初の試みはMock、指定されたシーケンス オブジェクトに呼び出しを登録する特殊なサブクラスを使用することです。これは、任意の共有シーケンスにすることができます。

from copy import deepcopy
import mock

class CallRegisterMock(mock.MagicMock):
    """ A mock object that registers each call. """

    def __init__(self, call_register, *args, **kwargs):
        super(CallRegisterMock, self).__init__(*args, **kwargs)

        self.call_register = call_register

    def __call__(self, *args, **kwargs):
        args = deepcopy(args)
        kwargs = deepcopy(kwargs)
        call = mock.call(*args, **kwargs)
        qualified_call = (self, call)
        self.call_register.append(qualified_call)
        super(CallRegisterMock, self).__call__(*args, **kwargs)

これには欠点があります。

  • 1つまたは複数の車輪を再発明している可能性があります。(そう思う場合は、より良い答えを追加してください。)
于 2014-12-05T00:32:21.287 に答える