unittest.mock —モックオブジェクトライブラリ—Pythonドキュメント

提供:Dev Guides
< PythonPython/docs/3.8/library/unittest.mock
移動先:案内検索

unittest.mock —モックオブジェクトライブラリ

バージョン3.3の新機能。


ソースコード: :source: `Lib / unittest / mock.py`



unittest.mock は、Pythonでテストするためのライブラリです。 これにより、テスト対象のシステムの一部をモックオブジェクトに置き換えて、それらがどのように使用されたかについてアサーションを作成できます。

unittest.mock は、コア Mock クラスを提供し、テストスイート全体でスタブのホストを作成する必要をなくします。 アクションを実行した後、使用されたメソッド/属性とそれらが呼び出された引数についてアサーションを作成できます。 通常の方法で戻り値を指定し、必要な属性を設定することもできます。

さらに、モックは、テストの範囲内でパッチ適用モジュールとクラスレベルの属性を処理する patch()デコレータと、一意のオブジェクトを作成するための sentinel を提供します。 MockMagicMockpatch()の使用例については、クイックガイドを参照してください。

モックは非常に使いやすく、 unittest で使用するように設計されています。 モックは、多くのモックフレームワークで使用されている「レコード->リプレイ」ではなく、「アクション->アサーション」パターンに基づいています。

以前のバージョンのPythonには unittest.mock のバックポートがあり、PyPI モックとして利用できます。

クイックガイド

Mock および MagicMock オブジェクトは、アクセス時にすべての属性とメソッドを作成し、それらの使用方法の詳細を保存します。 それらを構成して、戻り値を指定したり、使用可能な属性を制限したりして、それらがどのように使用されたかについてアサーションを作成できます。

>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')

side_effectを使用すると、モックが呼び出されたときに例外を発生させるなどの副作用を実行できます。

>>> mock = Mock(side_effect=KeyError('foo'))
>>> mock()
Traceback (most recent call last):
 ...
KeyError: 'foo'
>>> values = {'a': 1, 'b': 2, 'c': 3}
>>> def side_effect(arg):
...     return values[arg]
...
>>> mock.side_effect = side_effect
>>> mock('a'), mock('b'), mock('c')
(1, 2, 3)
>>> mock.side_effect = [5, 4, 3, 2, 1]
>>> mock(), mock(), mock()
(5, 4, 3)

モックには、それを構成してその動作を制御する方法が他にもたくさんあります。 たとえば、 spec 引数は、別のオブジェクトからその仕様を取得するようにモックを構成します。 仕様に存在しないモックの属性またはメソッドにアクセスしようとすると、 AttributeError で失敗します。

patch()デコレータ/コンテキストマネージャを使用すると、テスト対象のモジュール内のクラスまたはオブジェクトを簡単にモックできます。 指定したオブジェクトは、テスト中にモック(または他のオブジェクト)に置き換えられ、テストが終了すると復元されます。

>>> from unittest.mock import patch
>>> @patch('module.ClassName2')
... @patch('module.ClassName1')
... def test(MockClass1, MockClass2):
...     module.ClassName1()
...     module.ClassName2()
...     assert MockClass1 is module.ClassName1
...     assert MockClass2 is module.ClassName2
...     assert MockClass1.called
...     assert MockClass2.called
...
>>> test()

ノート

パッチデコレータをネストすると、モックは適用されたのと同じ順序でデコレートされた関数に渡されます(デコレータが適用される通常の Python の順序)。 これは下から上を意味するため、上記の例では、module.ClassName1のモックが最初に渡されます。

patch()では、検索される名前空間内のオブジェクトにパッチを適用することが重要です。 これは通常簡単ですが、クイックガイドについてはパッチを適用する場所をお読みください。


デコレータ patch()は、withステートメントのコンテキストマネージャとして使用できます。

>>> with patch.object(ProductionClass, 'method', return_value=None) as mock_method:
...     thing = ProductionClass()
...     thing.method(1, 2, 3)
...
>>> mock_method.assert_called_once_with(1, 2, 3)

スコープ中にディクショナリに値を設定し、テストの終了時にディクショナリを元の状態に復元するための patch.dict()もあります。

>>> foo = {'key': 'value'}
>>> original = foo.copy()
>>> with patch.dict(foo, {'newkey': 'newvalue'}, clear=True):
...     assert foo == {'newkey': 'newvalue'}
...
>>> assert foo == original

モックはPython マジックメソッドのモックをサポートします。 マジックメソッドを使用する最も簡単な方法は、 MagicMock クラスを使用することです。 それはあなたが次のようなことをすることを可能にします:

>>> mock = MagicMock()
>>> mock.__str__.return_value = 'foobarbaz'
>>> str(mock)
'foobarbaz'
>>> mock.__str__.assert_called_with()

モックを使用すると、関数(または他のモックインスタンス)をマジックメソッドに割り当てることができ、それらは適切に呼び出されます。 MagicMock クラスは、すべてのマジックメソッドが事前に作成されたモックバリアントです(とにかく、すべての便利なメソッド)。

以下は、通常のMockクラスでマジックメソッドを使用する例です。

>>> mock = Mock()
>>> mock.__str__ = Mock(return_value='wheeeeee')
>>> str(mock)
'wheeeeee'

テスト内のモックオブジェクトが、置き換えるオブジェクトと同じapiを持つようにするには、自動仕様を使用できます。 自動スペックは、パッチを適用する autospec 引数、または create_autospec()関数を使用して実行できます。 自動スペックは、置き換えるオブジェクトと同じ属性とメソッドを持つモックオブジェクトを作成し、関数とメソッド(コンストラクターを含む)は実際のオブジェクトと同じ呼び出しシグネチャを持ちます。

これにより、モックが正しく使用されていない場合、モックが本番コードと同じように失敗することが保証されます。

>>> from unittest.mock import create_autospec
>>> def function(a, b, c):
...     pass
...
>>> mock_function = create_autospec(function, return_value='fishy')
>>> mock_function(1, 2, 3)
'fishy'
>>> mock_function.assert_called_once_with(1, 2, 3)
>>> mock_function('wrong arguments')
Traceback (most recent call last):
 ...
TypeError: <lambda>() takes exactly 3 arguments (1 given)

create_autospec()は、__init__メソッドの署名をコピーするクラス、および__call__メソッドの署名をコピーする呼び出し可能オブジェクトでも使用できます。


モッククラス

Mock は、コード全体でスタブとテストダブルの使用を置き換えることを目的とした柔軟なモックオブジェクトです。 モックは呼び出し可能であり、アクセスすると新しいモックとして属性を作成します 1 。 同じ属性にアクセスすると、常に同じモックが返されます。 モックは、それらの使用方法を記録し、コードがそれらに対して何をしたかについてアサーションを作成できるようにします。

MagicMock は、 Mock のサブクラスであり、すべてのマジックメソッドが事前に作成されており、すぐに使用できます。 呼び出し不可能なバリアントもあります。呼び出し不可能なオブジェクトをモックアウトする場合に便利です: NonCallableMock および NonCallableMagicMock

patch()デコレータを使用すると、特定のモジュールのクラスを Mock オブジェクトに一時的に簡単に置き換えることができます。 デフォルトでは、 patch()MagicMock を作成します。 patch()new_callable 引数を使用して、 Mock の代替クラスを指定できます。

class unittest.mock.Mock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)

新しい Mock オブジェクトを作成します。 Mock は、モックオブジェクトの動作を指定するいくつかのオプションの引数を取ります。

  • spec :これは、文字列のリスト、またはモックオブジェクトの仕様として機能する既存のオブジェクト(クラスまたはインスタンス)のいずれかです。 オブジェクトを渡すと、オブジェクトでdirを呼び出すことによって文字列のリストが形成されます(サポートされていないマジック属性とメソッドを除く)。 このリストにない属性にアクセスすると、 AttributeError が発生します。

    spec が(文字列のリストではなく)オブジェクトである場合、 __ class __ はspecオブジェクトのクラスを返します。 これにより、モックは isinstance()テストに合格できます。

  • spec_setspec のより厳密なバリアント。 使用する場合、 set を実行しようとするか、 spec_set として渡されたオブジェクトにないモックの属性を取得しようとすると、 AttributeError が発生します。

  • side_effect :モックが呼び出されるたびに呼び出される関数。 side_effect 属性を参照してください。 例外を発生させたり、戻り値を動的に変更したりする場合に便利です。 この関数はモックと同じ引数で呼び出され、 DEFAULT を返さない限り、この関数の戻り値が戻り値として使用されます。

    または、 side_effect を例外クラスまたはインスタンスにすることもできます。 この場合、モックが呼び出されたときに例外が発生します。

    side_effect が反復可能である場合、モックへの各呼び出しは反復可能から次の値を返します。

    side_effect は、Noneに設定することでクリアできます。

  • return_value :モックが呼び出されたときに返される値。 デフォルトでは、これは新しいモックです(最初のアクセス時に作成されます)。 return_value 属性を参照してください。

  • 安全でない:デフォルトでは、属性が assert または assret で始まる場合、 AttributeError が発生します。 unsafe=Trueを渡すと、これらの属性にアクセスできるようになります。

    バージョン3.5の新機能。

  • wraps :モックオブジェクトをラップするアイテム。 wrapsNoneでない場合、モックを呼び出すと、ラップされたオブジェクトに呼び出しが渡されます(実際の結果が返されます)。 モックへの属性アクセスは、ラップされたオブジェクトの対応する属性をラップするモックオブジェクトを返します(したがって、存在しない属性にアクセスしようとすると、 AttributeError が発生します)。

    モックに明示的な return_value が設定されている場合、呼び出しはラップされたオブジェクトに渡されず、代わりに return_value が返されます。

  • name :モックに名前がある場合、それはモックのreprで使用されます。 これはデバッグに役立ちます。 名前は子モックに伝播されます。

モックは、任意のキーワード引数を使用して呼び出すこともできます。 これらは、モックが作成された後、モックに属性を設定するために使用されます。 詳細については、 configure_mock()メソッドを参照してください。

assert_called()

モックが少なくとも1回呼び出されたことを表明します。

>>> mock = Mock()
>>> mock.method()
<Mock name='mock.method()' id='...'>
>>> mock.method.assert_called()

バージョン3.6の新機能。

assert_called_once()

モックが1回だけ呼び出されたことを表明します。

>>> mock = Mock()
>>> mock.method()
<Mock name='mock.method()' id='...'>
>>> mock.method.assert_called_once()
>>> mock.method()
<Mock name='mock.method()' id='...'>
>>> mock.method.assert_called_once()
Traceback (most recent call last):
...
AssertionError: Expected 'method' to have been called once. Called 2 times.

バージョン3.6の新機能。

assert_called_with(*args, **kwargs)

このメソッドは、最後の呼び出しが特定の方法で行われたことを表明する便利な方法です。

>>> mock = Mock()
>>> mock.method(1, 2, 3, test='wow')
<Mock name='mock.method()' id='...'>
>>> mock.method.assert_called_with(1, 2, 3, test='wow')
assert_called_once_with(*args, **kwargs)

モックが1回だけ呼び出され、その呼び出しが指定された引数で行われたことを表明します。

>>> mock = Mock(return_value=None)
>>> mock('foo', bar='baz')
>>> mock.assert_called_once_with('foo', bar='baz')
>>> mock('other', bar='values')
>>> mock.assert_called_once_with('other', bar='values')
Traceback (most recent call last):
  ...
AssertionError: Expected 'mock' to be called once. Called 2 times.
assert_any_call(*args, **kwargs)

指定された引数でモックが呼び出されたことを表明します。

呼び出しが最新のものである場合にのみ渡される assert_called_with()および assert_called_once_with()とは異なり、モックが ever が呼び出された場合にアサートは渡されます。 assert_called_once_with()の場合、これも唯一の呼び出しである必要があります。

>>> mock = Mock(return_value=None)
>>> mock(1, 2, arg='thing')
>>> mock('some', 'thing', 'else')
>>> mock.assert_any_call(1, 2, arg='thing')
assert_has_calls(calls, any_order=False)

指定された呼び出しでモックが呼び出されたことを表明します。 mock_calls リストで呼び出しがチェックされます。

any_order がfalseの場合、呼び出しは順次である必要があります。 指定された呼び出しの前後に追加の呼び出しが存在する可能性があります。

any_order がtrueの場合、呼び出しは任意の順序にすることができますが、すべて mock_calls に表示される必要があります。

>>> mock = Mock(return_value=None)
>>> mock(1)
>>> mock(2)
>>> mock(3)
>>> mock(4)
>>> calls = [call(2), call(3)]
>>> mock.assert_has_calls(calls)
>>> calls = [call(4), call(2), call(3)]
>>> mock.assert_has_calls(calls, any_order=True)
assert_not_called()

モックが呼び出されたことはないと主張します。

>>> m = Mock()
>>> m.hello.assert_not_called()
>>> obj = m.hello()
>>> m.hello.assert_not_called()
Traceback (most recent call last):
  ...
AssertionError: Expected 'hello' to not have been called. Called 1 times.

バージョン3.5の新機能。

reset_mock(*, return_value=False, side_effect=False)

reset_mockメソッドは、モックオブジェクトのすべての呼び出し属性をリセットします。

>>> mock = Mock(return_value=None)
>>> mock('hello')
>>> mock.called
True
>>> mock.reset_mock()
>>> mock.called
False

バージョン3.6で変更: reset_mock関数に2つのキーワードのみの引数を追加しました。

これは、同じオブジェクトを再利用する一連のアサーションを作成する場合に役立ちます。 reset_mock() は、戻り値、 side_effect 、またはデフォルトで通常の割り当てを使用して設定した子属性をクリアしないことに注意してください。 return_value または side_effect をリセットする場合は、対応するパラメーターをTrueとして渡します。 子モックと戻り値モック(存在する場合)もリセットされます。

ノート

return_value および side_effect はキーワードのみの引数です。

mock_add_spec(spec, spec_set=False)

モックにスペックを追加します。 spec は、オブジェクトまたは文字列のリストのいずれかです。 spec の属性のみが、モックから属性としてフェッチできます。

spec_set がtrueの場合、仕様の属性のみを設定できます。

attach_mock(mock, attribute)

名前と親を置き換えて、このモックの属性としてモックを添付します。 添付されたモックへの呼び出しは、このモックの method_calls および mock_calls 属性に記録されます。

configure_mock(**kwargs)

キーワード引数を使用してモックに属性を設定します。

属性と戻り値および副作用は、標準のドット表記を使用し、メソッド呼び出しで辞書を解凍することで、子モックに設定できます。

>>> mock = Mock()
>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock.configure_mock(**attrs)
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
  ...
KeyError

モックへのコンストラクター呼び出しでも同じことが実現できます。

>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock = Mock(some_attribute='eggs', **attrs)
>>> mock.some_attribute
'eggs'
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
  ...
KeyError

configure_mock()は、モックの作成後に構成を簡単に行えるようにするために存在します。

__dir__()

Mock オブジェクトは、dir(some_mock)の結果を有用な結果に制限します。 spec のモックの場合、これにはモックに許可されているすべての属性が含まれます。

このフィルタリングの機能とオフにする方法については、 FILTER_DIR を参照してください。

_get_child_mock(**kw)

属性と戻り値の子モックを作成します。 デフォルトでは、子モックは親と同じタイプになります。 モックのサブクラスは、これをオーバーライドして、子モックの作成方法をカスタマイズしたい場合があります。

呼び出し不可能なモックの場合、(カスタムサブクラスではなく)呼び出し可能なバリアントが使用されます。

called

モックオブジェクトが呼び出されたかどうかを表すブール値:

>>> mock = Mock(return_value=None)
>>> mock.called
False
>>> mock()
>>> mock.called
True
call_count

モックオブジェクトが呼び出された回数を示す整数:

>>> mock = Mock(return_value=None)
>>> mock.call_count
0
>>> mock()
>>> mock()
>>> mock.call_count
2
return_value

これを設定して、モックを呼び出して返される値を構成します。

>>> mock = Mock()
>>> mock.return_value = 'fish'
>>> mock()
'fish'

デフォルトの戻り値はモックオブジェクトであり、通常の方法で構成できます。

>>> mock = Mock()
>>> mock.return_value.attribute = sentinel.Attribute
>>> mock.return_value()
<Mock name='mock()()' id='...'>
>>> mock.return_value.assert_called_with()

return_value もコンストラクターで設定できます。

>>> mock = Mock(return_value=3)
>>> mock.return_value
3
>>> mock()
3
side_effect

これは、モックが呼び出されたときに呼び出される関数、反復可能、または発生する例外(クラスまたはインスタンス)のいずれかです。

関数を渡すと、モックと同じ引数で呼び出され、関数が DEFAULT シングルトンを返さない限り、モックの呼び出しは関数が返すものをすべて返します。 関数が DEFAULT を返す場合、モックは通常の値を返します( return_value から)。

iterableを渡すと、呼び出しごとに値を生成する必要があるイテレータを取得するために使用されます。 この値は、発生する例外インスタンス、またはモックの呼び出しから返される値のいずれかです( DEFAULT の処理は関数の場合と同じです)。

例外を発生させるモックの例(APIの例外処理をテストするため):

>>> mock = Mock()
>>> mock.side_effect = Exception('Boom!')
>>> mock()
Traceback (most recent call last):
  ...
Exception: Boom!

side_effect を使用して、一連の値を返します。

>>> mock = Mock()
>>> mock.side_effect = [3, 2, 1]
>>> mock(), mock(), mock()
(3, 2, 1)

呼び出し可能オブジェクトの使用:

>>> mock = Mock(return_value=3)
>>> def side_effect(*args, **kwargs):
...     return DEFAULT
...
>>> mock.side_effect = side_effect
>>> mock()
3

side_effect はコンストラクターで設定できます。 これは、モックが呼び出された値に1を追加し、それを返す例です。

>>> side_effect = lambda value: value + 1
>>> mock = Mock(side_effect=side_effect)
>>> mock(3)
4
>>> mock(-8)
-7

side_effectNoneに設定すると、次のようにクリアされます。

>>> m = Mock(side_effect=KeyError, return_value=3)
>>> m()
Traceback (most recent call last):
 ...
KeyError
>>> m.side_effect = None
>>> m()
3
call_args

これは、None(モックが呼び出されていない場合)、またはモックが最後に呼び出された引数のいずれかです。 これはタプルの形式になります。argsプロパティからもアクセスできる最初のメンバーは、モックが呼び出された順序付き引数(または空のタプル)であり、2番目のメンバーはkwargsプロパティからもアクセスできます。これは、任意のキーワード引数(または空の辞書)です。

>>> mock = Mock(return_value=None)
>>> print(mock.call_args)
None
>>> mock()
>>> mock.call_args
call()
>>> mock.call_args == ()
True
>>> mock(3, 4)
>>> mock.call_args
call(3, 4)
>>> mock.call_args == ((3, 4),)
True
>>> mock.call_args.args
(3, 4)
>>> mock.call_args.kwargs
{}
>>> mock(3, 4, 5, key='fish', next='w00t!')
>>> mock.call_args
call(3, 4, 5, key='fish', next='w00t!')
>>> mock.call_args.args
(3, 4, 5)
>>> mock.call_args.kwargs
{'key': 'fish', 'next': 'w00t!'}

call_args は、リスト call_args_listmethod_calls 、および mock_calls のメンバーとともに、 call オブジェクトです。 これらはタプルであるため、展開して個々の引数を取得し、より複雑なアサーションを作成できます。 タプルとしての呼び出しを参照してください。

バージョン3.8で変更: argsおよびkwargsプロパティが追加されました。

call_args_list

これは、モックオブジェクトに対して順番に行われたすべての呼び出しのリストです(したがって、リストの長さは、呼び出された回数です)。 呼び出しが行われる前は、空のリストです。 call オブジェクトは、 call_args_list と比較するための呼び出しのリストを簡単に作成するために使用できます。

>>> mock = Mock(return_value=None)
>>> mock()
>>> mock(3, 4)
>>> mock(key='fish', next='w00t!')
>>> mock.call_args_list
[call(), call(3, 4), call(key='fish', next='w00t!')]
>>> expected = [(), ((3, 4),), ({'key': 'fish', 'next': 'w00t!'},)]
>>> mock.call_args_list == expected
True

call_args_list のメンバーは、 call オブジェクトです。 これらは、個々の引数を取得するためのタプルとして解凍できます。 タプルとしての呼び出しを参照してください。

method_calls

モックは、自身への呼び出しを追跡するだけでなく、メソッドと属性、およびそれらのメソッドと属性への呼び出しも追跡します。

>>> mock = Mock()
>>> mock.method()
<Mock name='mock.method()' id='...'>
>>> mock.property.method.attribute()
<Mock name='mock.property.method.attribute()' id='...'>
>>> mock.method_calls
[call.method(), call.property.method.attribute()]

method_calls のメンバーは call オブジェクトです。 これらは、個々の引数を取得するためのタプルとして解凍できます。 タプルとしての呼び出しを参照してください。

mock_calls

mock_calls は、モックオブジェクト、そのメソッド、マジックメソッドおよびの戻り値モックへのすべての呼び出しを記録します。

>>> mock = MagicMock()
>>> result = mock(1, 2, 3)
>>> mock.first(a=3)
<MagicMock name='mock.first()' id='...'>
>>> mock.second()
<MagicMock name='mock.second()' id='...'>
>>> int(mock)
1
>>> result(1)
<MagicMock name='mock()()' id='...'>
>>> expected = [call(1, 2, 3), call.first(a=3), call.second(),
... call.__int__(), call()(1)]
>>> mock.mock_calls == expected
True

mock_calls のメンバーは、 call オブジェクトです。 これらは、個々の引数を取得するためのタプルとして解凍できます。 タプルとしての呼び出しを参照してください。

ノート

mock_calls が記録される方法は、ネストされた呼び出しが行われる場合、祖先呼び出しのパラメーターが記録されないため、常に等しく比較されることを意味します。

>>> mock = MagicMock()
>>> mock.top(a=3).bottom()
<MagicMock name='mock.top().bottom()' id='...'>
>>> mock.mock_calls
[call.top(a=3), call.top().bottom()]
>>> mock.mock_calls[-1] == call.top(a=-1).bottom()
True
__class__

通常、オブジェクトの __ class __ 属性はそのタイプを返します。 specのモックオブジェクトの場合、__class__は代わりにスペッククラスを返します。 これにより、モックオブジェクトは、置き換え/マスカレードするオブジェクトの isinstance()テストに合格できます。

>>> mock = Mock(spec=3)
>>> isinstance(mock, int)
True

__ class __ はに割り当てることができます。これにより、モックは仕様を使用せずに isinstance()チェックに合格できます。

>>> mock = Mock()
>>> mock.__class__ = dict
>>> isinstance(mock, dict)
True
class unittest.mock.NonCallableMock(spec=None, wraps=None, name=None, spec_set=None, **kwargs)
モックの呼び出し不可能なバージョン。 コンストラクターパラメーターは、 Mock と同じ意味を持ちますが、 return_valueside_effect は、呼び出し不可能なモックでは意味がありません。

クラスまたはインスタンスをspecまたはspec_setとして使用するモックオブジェクトは、 isinstance()テストに合格できます。

>>> mock = Mock(spec=SomeClass)
>>> isinstance(mock, SomeClass)
True
>>> mock = Mock(spec_set=SomeClass())
>>> isinstance(mock, SomeClass)
True

Mock クラスは、モックマジックメソッドをサポートしています。 詳細については、マジックメソッドを参照してください。

モッククラスと patch()デコレータはすべて、設定のために任意のキーワード引数を取ります。 patch()デコレータの場合、キーワードは作成中のモックのコンストラクタに渡されます。 キーワード引数は、モックの属性を構成するためのものです。

>>> m = MagicMock(attribute=3, other='fish')
>>> m.attribute
3
>>> m.other
'fish'

ドット付き表記を使用して、子モックの戻り値と副作用を同じ方法で設定できます。 呼び出しでドット名を直接使用することはできないため、辞書を作成し、**を使用して解凍する必要があります。

>>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> mock = Mock(some_attribute='eggs', **attrs)
>>> mock.some_attribute
'eggs'
>>> mock.method()
3
>>> mock.other()
Traceback (most recent call last):
  ...
KeyError

spec (または spec_set )で作成された呼び出し可能なモックは、モックへの呼び出しを照合するときに仕様オブジェクトの署名をイントロスペクトします。 したがって、位置的に渡されたか名前で渡されたかに関係なく、実際の呼び出しの引数と一致する可能性があります。

>>> def f(a, b, c): pass
...
>>> mock = Mock(spec=f)
>>> mock(1, 2, c=3)
<Mock name='mock()' id='140161580456576'>
>>> mock.assert_called_with(1, 2, 3)
>>> mock.assert_called_with(a=1, b=2, c=3)

これは、 assert_called_with()assert_called_once_with()assert_has_calls()、および assert_any_call()に適用されます。 Autospeccing の場合、モックオブジェクトのメソッド呼び出しにも適用されます。

バージョン3.4で変更:指定および自動指定のモックオブジェクトに署名のイントロスペクションを追加しました。


class unittest.mock.PropertyMock(*args, **kwargs)

クラスのプロパティまたはその他の記述子として使用することを目的としたモック。 PropertyMock は、__get__()および__set__()メソッドを提供するため、フェッチ時に戻り値を指定できます。

オブジェクトから PropertyMock インスタンスをフェッチすると、引数なしでモックが呼び出されます。 設定すると、設定されている値でモックが呼び出されます。

>>> class Foo:
...     @property
...     def foo(self):
...         return 'something'
...     @foo.setter
...     def foo(self, value):
...         pass
...
>>> with patch('__main__.Foo.foo', new_callable=PropertyMock) as mock_foo:
...     mock_foo.return_value = 'mockity-mock'
...     this_foo = Foo()
...     print(this_foo.foo)
...     this_foo.foo = 6
...
mockity-mock
>>> mock_foo.mock_calls
[call(), call(6)]

モック属性の格納方法が原因で、 PropertyMock をモックオブジェクトに直接アタッチすることはできません。 代わりに、モックタイプのオブジェクトにアタッチできます。

>>> m = MagicMock()
>>> p = PropertyMock(return_value=3)
>>> type(m).foo = p
>>> m.foo
3
>>> p.assert_called_once_with()
class unittest.mock.AsyncMock(spec=None, side_effect=None, return_value=DEFAULT, wraps=None, name=None, spec_set=None, unsafe=False, **kwargs)

Mock の非同期バージョン。 AsyncMock オブジェクトは、オブジェクトが非同期関数として認識されるように動作し、呼び出しの結果が待機可能です。

>>> mock = AsyncMock()
>>> asyncio.iscoroutinefunction(mock)
True
>>> inspect.isawaitable(mock())  
True

mock()の結果は非同期関数であり、待機後にside_effectまたはreturn_valueの結果になります。

  • side_effectが関数の場合、非同期関数はその関数の結果を返します。

  • side_effectが例外の場合、非同期関数は例外を発生させます。

  • side_effectが反復可能である場合、非同期関数は反復可能の次の値を返しますが、結果のシーケンスが使い果たされると、StopAsyncIterationはすぐに発生します。

  • side_effectが定義されていない場合、async関数はreturn_valueで定義された値を返すため、デフォルトでは、async関数は新しい AsyncMock オブジェクトを返します。

Mock または MagicMockspec を非同期関数に設定すると、呼び出し後にコルーチンオブジェクトが返されます。

>>> async def async_func(): pass
...
>>> mock = MagicMock(async_func)
>>> mock
<MagicMock spec='function' id='...'>
>>> mock()  
<coroutine object AsyncMockMixin._mock_call at ...>

MockMagicMock 、または AsyncMockspec を非同期および同期関数を持つクラスに設定すると、同期関数が自動的に検出され、 MagicMock (親モックが AsyncMock または MagicMock の場合)または Mock (親モックが Mockの場合)として設定します。 )。 すべての非同期関数は AsyncMock になります。

>>> class ExampleClass:
...     def sync_foo():
...         pass
...     async def async_foo():
...         pass
...
>>> a_mock = AsyncMock(ExampleClass)
>>> a_mock.sync_foo
<MagicMock name='mock.sync_foo' id='...'>
>>> a_mock.async_foo
<AsyncMock name='mock.async_foo' id='...'>
>>> mock = Mock(ExampleClass)
>>> mock.sync_foo
<Mock name='mock.sync_foo' id='...'>
>>> mock.async_foo
<AsyncMock name='mock.async_foo' id='...'>

バージョン3.8の新機能。

assert_awaited()

モックが少なくとも1回は待機していたことを表明します。 これは呼び出されたオブジェクトとは別であることに注意してください。awaitキーワードを使用する必要があります。

>>> mock = AsyncMock()
>>> async def main(coroutine_mock):
...     await coroutine_mock
...
>>> coroutine_mock = mock()
>>> mock.called
True
>>> mock.assert_awaited()
Traceback (most recent call last):
...
AssertionError: Expected mock to have been awaited.
>>> asyncio.run(main(coroutine_mock))
>>> mock.assert_awaited()
assert_awaited_once()

モックが1回だけ待っていたことを主張します。

>>> mock = AsyncMock()
>>> async def main():
...     await mock()
...
>>> asyncio.run(main())
>>> mock.assert_awaited_once()
>>> asyncio.run(main())
>>> mock.method.assert_awaited_once()
Traceback (most recent call last):
...
AssertionError: Expected mock to have been awaited once. Awaited 2 times.
assert_awaited_with(*args, **kwargs)

最後の待機が指定された引数であったことを表明します。

>>> mock = AsyncMock()
>>> async def main(*args, **kwargs):
...     await mock(*args, **kwargs)
...
>>> asyncio.run(main('foo', bar='bar'))
>>> mock.assert_awaited_with('foo', bar='bar')
>>> mock.assert_awaited_with('other')
Traceback (most recent call last):
...
AssertionError: expected call not found.
Expected: mock('other')
Actual: mock('foo', bar='bar')
assert_awaited_once_with(*args, **kwargs)

指定された引数を使用して、モックが1回だけ待機されたことを表明します。

>>> mock = AsyncMock()
>>> async def main(*args, **kwargs):
...     await mock(*args, **kwargs)
...
>>> asyncio.run(main('foo', bar='bar'))
>>> mock.assert_awaited_once_with('foo', bar='bar')
>>> asyncio.run(main('foo', bar='bar'))
>>> mock.assert_awaited_once_with('foo', bar='bar')
Traceback (most recent call last):
...
AssertionError: Expected mock to have been awaited once. Awaited 2 times.
assert_any_await(*args, **kwargs)

指定された引数でモックが待ち望まれていたことを表明します。

>>> mock = AsyncMock()
>>> async def main(*args, **kwargs):
...     await mock(*args, **kwargs)
...
>>> asyncio.run(main('foo', bar='bar'))
>>> asyncio.run(main('hello'))
>>> mock.assert_any_await('foo', bar='bar')
>>> mock.assert_any_await('other')
Traceback (most recent call last):
...
AssertionError: mock('other') await not found
assert_has_awaits(calls, any_order=False)

指定された呼び出しでモックが待機されていることをアサートします。 await_args_list リストで待機がチェックされます。

any_order がfalseの場合、待機はシーケンシャルである必要があります。 指定された待機の前後に追加の呼び出しが発生する可能性があります。

any_order がtrueの場合、待機は任意の順序にすることができますが、すべて await_args_list に表示される必要があります。

>>> mock = AsyncMock()
>>> async def main(*args, **kwargs):
...     await mock(*args, **kwargs)
...
>>> calls = [call("foo"), call("bar")]
>>> mock.assert_has_awaits(calls)
Traceback (most recent call last):
...
AssertionError: Awaits not found.
Expected: [call('foo'), call('bar')]
Actual: []
>>> asyncio.run(main('foo'))
>>> asyncio.run(main('bar'))
>>> mock.assert_has_awaits(calls)
assert_not_awaited()

モックが待たれなかったことを主張します。

>>> mock = AsyncMock()
>>> mock.assert_not_awaited()
reset_mock(*args, **kwargs)

Mock.reset_mock()を参照してください。 また、 await_count を0に、 await_args をNoneに設定し、 await_args_list をクリアします。

await_count

モックオブジェクトが待機された回数を追跡する整数。

>>> mock = AsyncMock()
>>> async def main():
...     await mock()
...
>>> asyncio.run(main())
>>> mock.await_count
1
>>> asyncio.run(main())
>>> mock.await_count
2
await_args

これは、None(モックが待機されていない場合)、またはモックが最後に待機された引数のいずれかです。 Mock.call_args と同じように機能します。

>>> mock = AsyncMock()
>>> async def main(*args):
...     await mock(*args)
...
>>> mock.await_args
>>> asyncio.run(main('foo'))
>>> mock.await_args
call('foo')
>>> asyncio.run(main('bar'))
>>> mock.await_args
call('bar')
await_args_list

これは、モックオブジェクトに対して順番に行われたすべての待機のリストです(したがって、リストの長さは、待機された回数です)。 待機が行われる前は、空のリストです。

>>> mock = AsyncMock()
>>> async def main(*args):
...     await mock(*args)
...
>>> mock.await_args_list
[]
>>> asyncio.run(main('foo'))
>>> mock.await_args_list
[call('foo')]
>>> asyncio.run(main('bar'))
>>> mock.await_args_list
[call('foo'), call('bar')]

呼び出し

モックオブジェクトは呼び出し可能です。 呼び出しは、 return_value 属性として設定された値を返します。 デフォルトの戻り値は新しいモックオブジェクトです。 戻り値に最初にアクセスしたときに(明示的にまたはモックを呼び出すことによって)作成されますが、保存され、毎回同じ値が返されます。

オブジェクトに対して行われた呼び出しは、 call_argscall_args_list などの属性に記録されます。

side_effect が設定されている場合、通話が録音された後に呼び出されるため、side_effectで例外が発生しても、通話は引き続き録音されます。

モックを呼び出したときに例外を発生させる最も簡単な方法は、 side_effect を例外クラスまたはインスタンスにすることです。

>>> m = MagicMock(side_effect=IndexError)
>>> m(1, 2, 3)
Traceback (most recent call last):
  ...
IndexError
>>> m.mock_calls
[call(1, 2, 3)]
>>> m.side_effect = KeyError('Bang!')
>>> m('two', 'three', 'four')
Traceback (most recent call last):
  ...
KeyError: 'Bang!'
>>> m.mock_calls
[call(1, 2, 3), call('two', 'three', 'four')]

side_effectが関数の場合、その関数が返すものはすべて、モックリターンを呼び出すものです。 side_effect関数は、モックと同じ引数で呼び出されます。 これにより、入力に基づいて、呼び出しの戻り値を動的に変更できます。

>>> def side_effect(value):
...     return value + 1
...
>>> m = MagicMock(side_effect=side_effect)
>>> m(1)
2
>>> m(2)
3
>>> m.mock_calls
[call(1), call(2)]

モックがデフォルトの戻り値(新しいモック)または設定された戻り値を引き続き返すようにする場合は、2つの方法があります。 side_effectの内側からmock.return_valueを返すか、 DEFAULT を返します。

>>> m = MagicMock()
>>> def side_effect(*args, **kwargs):
...     return m.return_value
...
>>> m.side_effect = side_effect
>>> m.return_value = 3
>>> m()
3
>>> def side_effect(*args, **kwargs):
...     return DEFAULT
...
>>> m.side_effect = side_effect
>>> m()
3

side_effectを削除してデフォルトの動作に戻すには、side_effectNoneに設定します。

>>> m = MagicMock(return_value=6)
>>> def side_effect(*args, **kwargs):
...     return 3
...
>>> m.side_effect = side_effect
>>> m()
3
>>> m.side_effect = None
>>> m()
6

side_effectは、任意の反復可能なオブジェクトにすることもできます。 モックを繰り返し呼び出すと、イテラブルから値が返されます(イテラブルが使い果たされ、 StopIteration が発生するまで)。

>>> m = MagicMock(side_effect=[1, 2, 3])
>>> m()
1
>>> m()
2
>>> m()
3
>>> m()
Traceback (most recent call last):
  ...
StopIteration

iterableのいずれかのメンバーが例外である場合、それらは返される代わりに発生します。

>>> iterable = (33, ValueError, 66)
>>> m = MagicMock(side_effect=iterable)
>>> m()
33
>>> m()
Traceback (most recent call last):
 ...
ValueError
>>> m()
66

属性の削除

モックオブジェクトは、オンデマンドで属性を作成します。 これにより、あらゆるタイプのオブジェクトのふりをすることができます。

モックオブジェクトがFalsehasattr()呼び出しに返すか、属性がフェッチされたときに AttributeError を発生させることができます。 これは、モックのspecとしてオブジェクトを提供することで実行できますが、必ずしも便利なわけではありません。

属性を削除して「ブロック」します。 削除されると、属性にアクセスすると AttributeError が発生します。

>>> mock = MagicMock()
>>> hasattr(mock, 'm')
True
>>> del mock.m
>>> hasattr(mock, 'm')
False
>>> del mock.f
>>> mock.f
Traceback (most recent call last):
    ...
AttributeError: f

モック名と名前属性

「name」は Mock コンストラクターの引数であるため、モックオブジェクトに「name」属性を持たせたい場合は、作成時にそれを渡すことはできません。 2つの選択肢があります。 1つのオプションは、 configure_mock()を使用することです。

>>> mock = MagicMock()
>>> mock.configure_mock(name='my_name')
>>> mock.name
'my_name'

より簡単なオプションは、モックの作成後に「name」属性を設定することです。

>>> mock = MagicMock()
>>> mock.name = "foo"

属性としてモックをアタッチする

別のモックの属性として(または戻り値として)モックをアタッチすると、そのモックの「子」になります。 子への呼び出しは、親の method_calls および mock_calls 属性に記録されます。 これは、子モックを構成してからそれらを親にアタッチする場合、または子へのすべての呼び出しを記録し、モック間の呼び出しの順序についてアサーションを作成できるようにする親にモックをアタッチする場合に役立ちます。

>>> parent = MagicMock()
>>> child1 = MagicMock(return_value=None)
>>> child2 = MagicMock(return_value=None)
>>> parent.child1 = child1
>>> parent.child2 = child2
>>> child1(1)
>>> child2(2)
>>> parent.mock_calls
[call.child1(1), call.child2(2)]

これの例外は、モックに名前がある場合です。 これにより、何らかの理由で「子育て」を起こしたくない場合に、「子育て」を防ぐことができます。

>>> mock = MagicMock()
>>> not_a_child = MagicMock(name='not-a-child')
>>> mock.attribute = not_a_child
>>> mock.attribute()
<MagicMock name='not-a-child()' id='...'>
>>> mock.mock_calls
[]

patch()によって作成されたモックには、自動的に名前が付けられます。 名前のあるモックを親にアタッチするには、 attach_mock()メソッドを使用します。

>>> thing1 = object()
>>> thing2 = object()
>>> parent = MagicMock()
>>> with patch('__main__.thing1', return_value=None) as child1:
...     with patch('__main__.thing2', return_value=None) as child2:
...         parent.attach_mock(child1, 'child1')
...         parent.attach_mock(child2, 'child2')
...         child1('one')
...         child2('two')
...
>>> parent.mock_calls
[call.child1('one'), call.child2('two')]
1
唯一の例外は、魔法のメソッドと属性(先頭と末尾に二重下線があるもの)です。 モックはこれらを作成しませんが、代わりに AttributeError を発生させます。 これは、インタプリタがこれらのメソッドを暗黙的に要求することが多く、魔法のメソッドを期待しているときに非常にが混乱して新しいモックオブジェクトを取得するためです。 マジックメソッドのサポートが必要な場合は、マジックメソッドを参照してください。


パッチャー

パッチデコレータは、オブジェクトがデコレートする関数の範囲内でのみオブジェクトにパッチを適用するために使用されます。 例外が発生した場合でも、パッチ解除は自動的に処理されます。 これらの関数はすべて、ステートメントとともに、またはクラスデコレータとして使用することもできます。

パッチ

ノート

patch()は簡単に使用できます。 重要なのは、適切な名前空間でパッチを適用することです。 パッチを適用する場所のセクションを参照してください。


unittest.mock.patch(target, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)

patch()は、関数デコレータ、クラスデコレータ、またはコンテキストマネージャとして機能します。 関数の本体内またはwithステートメント内で、 targetnew オブジェクトのパッチが適用されます。 function / withステートメントが終了すると、パッチは元に戻されます。

new を省略すると、パッチが適用されたオブジェクトが非同期関数の場合は AsyncMock に、それ以外の場合は MagicMock に置き換えられます。 patch()がデコレータとして使用され、 new が省略されている場合、作成されたモックは、装飾された関数への追加の引数として渡されます。 patch()がコンテキストマネージャーとして使用されている場合、作成されたモックはコンテキストマネージャーによって返されます。

target は、'package.module.ClassName'の形式の文字列である必要があります。 target がインポートされ、指定されたオブジェクトが new オブジェクトに置き換えられるため、 target は、 patch()を呼び出す環境からインポート可能である必要があります。 から。 ターゲットは、装飾時ではなく、装飾された関数の実行時にインポートされます。

spec および spec_set キーワード引数は、パッチによって作成されている場合、 MagicMock に渡されます。

さらに、spec=Trueまたはspec_set=Trueを渡すことができます。これにより、パッチは、spec / spec_setオブジェクトとしてモックされているオブジェクトに渡されます。

new_callable を使用すると、 new オブジェクトを作成するために呼び出される別のクラスまたは呼び出し可能オブジェクトを指定できます。 デフォルトでは、 AsyncMock が非同期関数に使用され、 MagicMock が残りに使用されます。

spec のより強力な形式は、 autospec です。 autospec=Trueを設定すると、置き換えられるオブジェクトのスペックを使用してモックが作成されます。 モックのすべての属性には、置き換えられるオブジェクトの対応する属性の仕様も含まれます。 モックされるメソッドと関数は引数がチェックされ、間違ったシグネチャで呼び出されると TypeError が発生します。 クラスを置き換えるモックの場合、それらの戻り値(「インスタンス」)はクラスと同じ仕様になります。 create_autospec()関数および Autospeccing を参照してください。

autospec=Trueの代わりに、autospec=some_objectを渡して、置き換えられるオブジェクトの代わりに任意のオブジェクトを仕様として使用できます。

デフォルトでは、 patch()は存在しない属性の置き換えに失敗します。 create=Trueを渡し、属性が存在しない場合、patchは、パッチが適用された関数が呼び出されたときに属性を作成し、パッチが適用された関数が終了した後に属性を再度削除します。 これは、本番コードが実行時に作成する属性に対するテストを作成する場合に役立ちます。 危険な場合があるため、デフォルトではオフになっています。 オンにすると、実際には存在しないAPIに対して合格テストを作成できます。

ノート

バージョン3.5で変更:モジュールのビルトインにパッチを適用する場合、create=Trueを渡す必要はなく、デフォルトで追加されます。

パッチはTestCaseクラスのデコレータとして使用できます。 これは、クラス内の各テストメソッドを装飾することによって機能します。 これにより、テストメソッドが共通のパッチセットを共有する場合の定型コードが削減されます。 patch()は、patch.TEST_PREFIXで始まるメソッド名を探すことによってテストを検索します。 デフォルトでは、これは'test'であり、 unittest がテストを見つける方法と一致します。 patch.TEST_PREFIXを設定すると、代替プレフィックスを指定できます。

パッチは、withステートメントを使用してコンテキストマネージャーとして使用できます。 ここで、パッチはwithステートメントの後のインデントされたブロックに適用されます。 「as」を使用すると、パッチが適用されたオブジェクトは「as」の後の名前にバインドされます。 patch()がモックオブジェクトを作成している場合に非常に便利です。

patch()は任意のキーワード引数を取ります。 これらは、構築時に Mock (または new_callable )に渡されます。

patch.dict(...)patch.multiple(...)、およびpatch.object(...)は、別のユースケースで使用できます。

patch()を関数デコレータとして使用し、モックを作成して、装飾された関数に渡します。

>>> @patch('__main__.SomeClass')
... def function(normal_argument, mock_class):
...     print(mock_class is SomeClass)
...
>>> function(None)
True

クラスにパッチを適用すると、クラスが MagicMock instance に置き換えられます。 テスト対象のコードでクラスがインスタンス化されている場合、使用されるのはモックの return_value になります。

クラスが複数回インスタンス化される場合は、 side_effect を使用して、毎回新しいモックを返すことができます。 または、 return_value を任意の値に設定することもできます。

パッチを適用したクラスのインスタンスのメソッドで戻り値を構成するには、return_valueでこれを行う必要があります。 例えば:

>>> class Class:
...     def method(self):
...         pass
...
>>> with patch('__main__.Class') as MockClass:
...     instance = MockClass.return_value
...     instance.method.return_value = 'foo'
...     assert Class() is instance
...     assert Class().method() == 'foo'
...

spec または spec_set を使用し、 patch()class を置き換える場合、作成されたモックの戻り値は同じスペック。

>>> Original = Class
>>> patcher = patch('__main__.Class', spec=True)
>>> MockClass = patcher.start()
>>> instance = MockClass()
>>> assert isinstance(instance, Original)
>>> patcher.stop()

new_callable 引数は、作成されたモックのデフォルトの MagicMock の代替クラスを使用する場合に役立ちます。 たとえば、 NonCallableMock を使用する場合は次のようになります。

>>> thing = object()
>>> with patch('__main__.thing', new_callable=NonCallableMock) as mock_thing:
...     assert thing is mock_thing
...     thing()
...
Traceback (most recent call last):
  ...
TypeError: 'NonCallableMock' object is not callable

別の使用例は、オブジェクトを io.StringIO インスタンスに置き換えることです。

>>> from io import StringIO
>>> def foo():
...     print('Something')
...
>>> @patch('sys.stdout', new_callable=StringIO)
... def test(mock_stdout):
...     foo()
...     assert mock_stdout.getvalue() == 'Something\n'
...
>>> test()

patch()がモックを作成している場合、最初に行う必要があるのはモックを構成することです。 その構成の一部は、パッチの呼び出しで実行できます。 呼び出しに渡す任意のキーワードは、作成されたモックに属性を設定するために使用されます。

>>> patcher = patch('__main__.thing', first='one', second='two')
>>> mock_thing = patcher.start()
>>> mock_thing.first
'one'
>>> mock_thing.second
'two'

子モックの return_valueside_effect など、作成されたモック属性の属性も構成できます。 これらは、キーワード引数として直接渡すために構文的に有効ではありませんが、キーとしてこれらを使用する辞書は、**を使用して patch()呼び出しに拡張できます。

>>> config = {'method.return_value': 3, 'other.side_effect': KeyError}
>>> patcher = patch('__main__.thing', **config)
>>> mock_thing = patcher.start()
>>> mock_thing.method()
3
>>> mock_thing.other()
Traceback (most recent call last):
  ...
KeyError

デフォルトでは、存在しないモジュール内の関数(またはクラス内のメソッドまたは属性)にパッチを適用しようとすると、 AttributeError で失敗します。

>>> @patch('sys.non_existing_attribute', 42)
... def test():
...     assert sys.non_existing_attribute == 42
...
>>> test()
Traceback (most recent call last):
  ...
AttributeError: <module 'sys' (built-in)> does not have the attribute 'non_existing'

ただし、 patch()の呼び出しにcreate=Trueを追加すると、前の例が期待どおりに機能します。

>>> @patch('sys.non_existing_attribute', 42, create=True)
... def test(mock_stdout):
...     assert sys.non_existing_attribute == 42
...
>>> test()

バージョン3.8で変更: patch()は、ターゲットが非同期関数の場合、 AsyncMock を返すようになりました。


patch.object

patch.object(target, attribute, new=DEFAULT, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)

オブジェクト( target )の名前付きメンバー( attribute )にモックオブジェクトをパッチします。

patch.object()は、デコレータ、クラスデコレータ、またはコンテキストマネージャとして使用できます。 引数 newspeccreatespec_setautospecnew_callable には patch()と同じ意味です。 patch()と同様に、 patch.object()は、作成するモックオブジェクトを構成するために任意のキーワード引数を取ります。

クラスデコレータとして使用する場合、 patch.object()は、ラップするメソッドを選択するためにpatch.TEST_PREFIXを尊重します。

patch.object()は、3つの引数または2つの引数を使用して呼び出すことができます。 3つの引数形式は、パッチを適用するオブジェクト、属性名、および属性を置き換えるオブジェクトを取ります。

2つの引数形式で呼び出す場合は、置換オブジェクトを省略します。モックが作成され、装飾された関数に追加の引数として渡されます。

>>> @patch.object(SomeClass, 'class_method')
... def test(mock_method):
...     SomeClass.class_method(3)
...     mock_method.assert_called_with(3)
...
>>> test()

speccreate 、および patch.object()に対するその他の引数は、 patch()の場合と同じ意味を持ちます。


patch.dict

patch.dict(in_dict, values=(), clear=False, **kwargs)

辞書または辞書のようなオブジェクトにパッチを適用し、テスト後に辞書を元の状態に復元します。

in_dict は、辞書またはコンテナーのようなマッピングにすることができます。 マッピングの場合は、少なくともアイテムの取得、設定、削除に加えて、キーの反復をサポートする必要があります。

in_dict は、辞書の名前を指定する文字列にすることもできます。辞書の名前は、インポートすることでフェッチされます。

values は、ディクショナリに設定する値のディクショナリにすることができます。 values は、(key, value)ペアの反復可能にすることもできます。

clear がtrueの場合、新しい値が設定される前にディクショナリがクリアされます。

patch.dict()を任意のキーワード引数で呼び出して、辞書に値を設定することもできます。

バージョン3.8で変更: patch.dict()は、コンテキストマネージャーとして使用されたときに、パッチが適用された辞書を返すようになりました。

patch.dict()は、コンテキストマネージャー、デコレーター、またはクラスデコレーターとして使用できます。

>>> foo = {}
>>> @patch.dict(foo, {'newkey': 'newvalue'})
... def test():
...     assert foo == {'newkey': 'newvalue'}
>>> test()
>>> assert foo == {}

クラスデコレータとして使用する場合、 patch.dict()は、ラップするメソッドを選択するためにpatch.TEST_PREFIX(デフォルトは'test')を尊重します。

>>> import os
>>> import unittest
>>> from unittest.mock import patch
>>> @patch.dict('os.environ', {'newkey': 'newvalue'})
... class TestSample(unittest.TestCase):
...     def test_sample(self):
...         self.assertEqual(os.environ['newkey'], 'newvalue')

テストに別のプレフィックスを使用する場合は、patch.TEST_PREFIXを設定することで、別のプレフィックスをパッチャーに通知できます。 の値を変更する方法の詳細については、 TEST_PREFIX を参照してください。

patch.dict()を使用して、メンバーを辞書に追加したり、テストで辞書を変更したりして、テストの終了時に辞書が確実に復元されるようにすることができます。

>>> foo = {}
>>> with patch.dict(foo, {'newkey': 'newvalue'}) as patched_foo:
...     assert foo == {'newkey': 'newvalue'}
...     assert patched_foo == {'newkey': 'newvalue'}
...     # You can add, update or delete keys of foo (or patched_foo, it's the same dict)
...     patched_foo['spam'] = 'eggs'
...
>>> assert foo == {}
>>> assert patched_foo == {}
>>> import os
>>> with patch.dict('os.environ', {'newkey': 'newvalue'}):
...     print(os.environ['newkey'])
...
newvalue
>>> assert 'newkey' not in os.environ

patch.dict()呼び出しでキーワードを使用して、辞書に値を設定できます。

>>> mymodule = MagicMock()
>>> mymodule.function.return_value = 'fish'
>>> with patch.dict('sys.modules', mymodule=mymodule):
...     import mymodule
...     mymodule.function('some', 'args')
...
'fish'

patch.dict()は、実際には辞書ではないオブジェクトのような辞書で使用できます。 少なくとも、アイテムの取得、設定、削除、および反復またはメンバーシップテストのいずれかをサポートする必要があります。 これは、マジックメソッド__getitem__()__setitem__()__delitem__()、および__iter__()または__contains__()のいずれかに対応します。

>>> class Container:
...     def __init__(self):
...         self.values = {}
...     def __getitem__(self, name):
...         return self.values[name]
...     def __setitem__(self, name, value):
...         self.values[name] = value
...     def __delitem__(self, name):
...         del self.values[name]
...     def __iter__(self):
...         return iter(self.values)
...
>>> thing = Container()
>>> thing['one'] = 1
>>> with patch.dict(thing, one=2, two=3):
...     assert thing['one'] == 2
...     assert thing['two'] == 3
...
>>> assert thing['one'] == 1
>>> assert list(thing) == ['one']

patch.multiple

patch.multiple(target, spec=None, create=False, spec_set=None, autospec=None, new_callable=None, **kwargs)

1回の呼び出しで複数のパッチを実行します。 パッチを適用するオブジェクト(インポートによってオブジェクトをフェッチするためのオブジェクトまたは文字列として)とパッチのキーワード引数が必要です。

with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'):
    ...

patch.multiple()でモックを作成する場合は、値として DEFAULT を使用します。 この場合、作成されたモックはキーワードによって装飾された関数に渡され、 patch.multiple()がコンテキストマネージャーとして使用されると辞書が返されます。

patch.multiple()は、デコレータ、クラスデコレータ、またはコンテキストマネージャとして使用できます。 引数 specspec_setcreateautospecnew_callable は、と同じ意味です。 patch()。 これらの引数は、 patch.multiple()によって実行される all パッチに適用されます。

クラスデコレータとして使用する場合、 patch.multiple()は、ラップするメソッドを選択するためにpatch.TEST_PREFIXを尊重します。

patch.multiple()でモックを作成する場合は、値として DEFAULT を使用できます。 patch.multiple()をデコレータとして使用する場合、作成されたモックはキーワードによってdecorated関数に渡されます。

>>> thing = object()
>>> other = object()

>>> @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)
... def test_function(thing, other):
...     assert isinstance(thing, MagicMock)
...     assert isinstance(other, MagicMock)
...
>>> test_function()

patch.multiple()は、他のpatchデコレータとネストできますが、 patch()によって作成された標準引数のいずれかの後にキーワードによって渡された引数を配置します。

>>> @patch('sys.exit')
... @patch.multiple('__main__', thing=DEFAULT, other=DEFAULT)
... def test_function(mock_exit, other, thing):
...     assert 'other' in repr(other)
...     assert 'thing' in repr(thing)
...     assert 'exit' in repr(mock_exit)
...
>>> test_function()

patch.multiple()がコンテキストマネージャーとして使用されている場合、コンテキストマネージャーによって返される値は、作成されたモックが名前でキー設定されている辞書です。

>>> with patch.multiple('__main__', thing=DEFAULT, other=DEFAULT) as values:
...     assert 'other' in repr(values['other'])
...     assert 'thing' in repr(values['thing'])
...     assert values['thing'] is thing
...     assert values['other'] is other
...

パッチ方法:開始と停止

すべてのパッチャーには、start()およびstop()メソッドがあります。 これらにより、setUpメソッドで、またはデコレータをネストせずに、またはステートメントを使用して複数のパッチを実行する場合に、パッチを適用することが簡単になります。

それらを使用するには、通常どおり patch()patch.object()、または patch.dict()を呼び出し、返された [への参照を保持します。 X135X]オブジェクト。 次に、start()を呼び出してパッチを配置し、stop()を呼び出してパッチを元に戻すことができます。

patch()を使用してモックを作成している場合は、patcher.startの呼び出しによってモックが返されます。

>>> patcher = patch('package.module.ClassName')
>>> from package import module
>>> original = module.ClassName
>>> new_mock = patcher.start()
>>> assert module.ClassName is not original
>>> assert module.ClassName is new_mock
>>> patcher.stop()
>>> assert module.ClassName is original
>>> assert module.ClassName is not new_mock

これの典型的な使用例は、TestCasesetUpメソッドで複数のパッチを実行する場合です。

>>> class MyTest(unittest.TestCase):
...     def setUp(self):
...         self.patcher1 = patch('package.module.Class1')
...         self.patcher2 = patch('package.module.Class2')
...         self.MockClass1 = self.patcher1.start()
...         self.MockClass2 = self.patcher2.start()
...
...     def tearDown(self):
...         self.patcher1.stop()
...         self.patcher2.stop()
...
...     def test_something(self):
...         assert package.module.Class1 is self.MockClass1
...         assert package.module.Class2 is self.MockClass2
...
>>> MyTest('test_something').run()

注意

この手法を使用する場合は、stopを呼び出して、パッチ適用が「取り消されている」ことを確認する必要があります。 setUpで例外が発生した場合、tearDownは呼び出されないため、これは想像以上に厄介な場合があります。 unittest.TestCase.addCleanup()を使用すると、これが簡単になります。

>>> class MyTest(unittest.TestCase):
...     def setUp(self):
...         patcher = patch('package.module.Class')
...         self.MockClass = patcher.start()
...         self.addCleanup(patcher.stop)
...
...     def test_something(self):
...         assert package.module.Class is self.MockClass
...

追加のボーナスとして、patcherオブジェクトへの参照を保持する必要がなくなりました。


patch.stopall()を使用して、開始されたすべてのパッチを停止することもできます。

patch.stopall()
アクティブなパッチをすべて停止します。 startで始まるパッチのみを停止します。


パッチビルトイン

モジュール内の任意のビルトインにパッチを適用できます。 次のサンプルパッチは、 ord()に組み込まれています。

>>> @patch('__main__.ord')
... def test(mock_ord):
...     mock_ord.return_value = 101
...     print(ord('c'))
...
>>> test()
101

TEST_PREFIX

すべてのパッチャーはクラスデコレーターとして使用できます。 このように使用すると、クラスのすべてのテストメソッドがラップされます。 パッチャーは、'test'で始まるメソッドをテストメソッドとして認識します。 これは、 unittest.TestLoader がデフォルトでテストメソッドを見つけるのと同じ方法です。

テストに別のプレフィックスを使用したい場合があります。 patch.TEST_PREFIXを設定することで、異なるプレフィックスをパッチャーに通知できます。

>>> patch.TEST_PREFIX = 'foo'
>>> value = 3
>>>
>>> @patch('__main__.value', 'not three')
... class Thing:
...     def foo_one(self):
...         print(value)
...     def foo_two(self):
...         print(value)
...
>>>
>>> Thing().foo_one()
not three
>>> Thing().foo_two()
not three
>>> value
3

ネストパッチデコレータ

複数のパッチを実行する場合は、デコレータを積み重ねるだけです。

このパターンを使用して、複数のパッチデコレータを積み重ねることができます。

>>> @patch.object(SomeClass, 'class_method')
... @patch.object(SomeClass, 'static_method')
... def test(mock1, mock2):
...     assert SomeClass.static_method is mock1
...     assert SomeClass.class_method is mock2
...     SomeClass.static_method('foo')
...     SomeClass.class_method('bar')
...     return mock1, mock2
...
>>> mock1, mock2 = test()
>>> mock1.assert_called_once_with('foo')
>>> mock2.assert_called_once_with('bar')

デコレータは下から上に向かって適用されることに注意してください。 これは、Pythonがデコレータを適用する標準的な方法です。 テスト関数に渡される作成されたモックの順序は、この順序と一致します。


パッチを当てる場所

patch()は、 name が指すオブジェクトを(一時的に)別のオブジェクトに変更することで機能します。 個々のオブジェクトを指す名前は多数存在する可能性があるため、パッチを適用するには、テスト対象のシステムで使用されている名前にパッチを適用する必要があります。

基本的な原則は、オブジェクトがルックアップされている場所にパッチを適用することです。これは、オブジェクトが定義されている場所と必ずしも同じではありません。 いくつかの例がこれを明確にするのに役立ちます。

次の構造でテストしたいプロジェクトがあるとします。

a.py
    -> Defines SomeClass

b.py
    -> from a import SomeClass
    -> some_function instantiates SomeClass

ここで、some_functionをテストしたいのですが、 patch()を使用してSomeClassをモックアウトしたいと思います。 問題は、モジュールbをインポートするときに、モジュールaからSomeClassをインポートする必要があることです。 patch()を使用してa.SomeClassをモックアウトした場合、テストには影響しません。 モジュールbにはすでに real SomeClassへの参照があり、パッチ適用は効果がなかったようです。

重要なのは、SomeClassが使用されている場所(または検索されている場所)にパッチを適用することです。 この場合、some_functionは、インポートしたモジュールbでSomeClassを実際に検索します。 パッチは次のようになります。

@patch('b.SomeClass')

ただし、from a import SomeClassの代わりにモジュールbがimport aを実行し、some_functiona.SomeClassを使用する代替シナリオを検討してください。 これらのインポートフォームは両方とも一般的です。 この場合、パッチを適用するクラスはモジュールで検索されているため、代わりにa.SomeClassにパッチを適用する必要があります。

@patch('a.SomeClass')

記述子とプロキシオブジェクトへのパッチ適用

patchpatch.object はどちらも、記述子(クラスメソッド、静的メソッド、およびプロパティ)に正しくパッチを適用して復元します。 これらは、インスタンスではなくクラスにパッチを適用する必要があります。 また、 django設定オブジェクトなど、属性アクセスをプロキシする一部のオブジェクトでも機能します。


MagicMockとマジックメソッドのサポート

魔法の方法をあざける

Mock は、「マジックメソッド」とも呼ばれるPythonプロトコルメソッドのモックをサポートします。 これにより、モックオブジェクトをPythonプロトコルを実装するコンテナやその他のオブジェクトに置き換えることができます。

マジックメソッドは通常のメソッド 2 とは異なる方法で検索されるため、このサポートは特別に実装されています。 これは、特定のマジックメソッドのみがサポートされていることを意味します。 サポートされているリストには、ほぼすべてが含まれています。 不足しているものがあればお知らせください。

関心のあるメソッドを関数またはモックインスタンスに設定することで、マジックメソッドをモックします。 関数を使用している場合は、最初の引数 3 として必須 selfを取る必要があります。

>>> def __str__(self):
...     return 'fooble'
...
>>> mock = Mock()
>>> mock.__str__ = __str__
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__str__ = Mock()
>>> mock.__str__.return_value = 'fooble'
>>> str(mock)
'fooble'
>>> mock = Mock()
>>> mock.__iter__ = Mock(return_value=iter([]))
>>> list(mock)
[]

このユースケースの1つは、 with ステートメントでコンテキストマネージャーとして使用されるオブジェクトをモックする場合です。

>>> mock = Mock()
>>> mock.__enter__ = Mock(return_value='foo')
>>> mock.__exit__ = Mock(return_value=False)
>>> with mock as m:
...     assert m == 'foo'
...
>>> mock.__enter__.assert_called_with()
>>> mock.__exit__.assert_called_with(None, None, None)

マジックメソッドの呼び出しは method_calls には表示されませんが、 mock_calls に記録されます。

ノート

spec キーワード引数を使用してモックを作成する場合、仕様に含まれていないマジックメソッドを設定しようとすると、 AttributeError が発生します。


サポートされているマジックメソッドの完全なリストは次のとおりです。

  • __hash____sizeof____repr____str__
  • __dir____format____subclasses__
  • __round____floor____trunc____ceil__
  • 比較:__lt____gt____le____ge____eq____ne__
  • コンテナ方式:__getitem____setitem____delitem____contains____len____iter__、 [X89X ]および__missing__
  • コンテキストマネージャー:__enter____exit____aenter____aexit__
  • 単項数値法:__neg____pos__、および__invert__
  • 数値法(右手およびインプレースバリアントを含む):__add____sub____mul____matmul____div__、[ X121X] 、__floordiv____mod____divmod____lshift____rshift____and__、[X202X ] 、__or__、および__pow__
  • 数値変換方法:__complex____int____float____index__
  • 記述子メソッド:__get____set__、および__delete__
  • 酸洗い:__reduce____reduce_ex____getinitargs____getnewargs____getstate____setstate__
  • ファイルシステムのパス表現:__fspath__
  • 非同期反復法:__aiter__および__anext__

バージョン3.8で変更: os.PathLike.__fspath__()のサポートが追加されました。


バージョン3.8で変更: __aenter____aexit____aiter____anext__のサポートが追加されました。


以下のメソッドは存在しますが、モックで使用されているか、動的に設定できないか、問題を引き起こす可能性があるため、サポートされていません

  • __getattr____setattr____init____new__
  • __prepare____instancecheck____subclasscheck____del__


マジックモック

MagicMockには、 MagicMockNonCallableMagicMock の2つのバリアントがあります。

class unittest.mock.MagicMock(*args, **kw)

MagicMockは、 Mock のサブクラスであり、ほとんどのマジックメソッドがデフォルトで実装されています。 マジックメソッドを自分で設定しなくても、MagicMockを使用できます。

コンストラクターのパラメーターは、 Mock の場合と同じ意味です。

spec または spec_set 引数を使用すると、仕様に存在するのみのマジックメソッドが作成されます。

class unittest.mock.NonCallableMagicMock(*args, **kw)

MagicMock の呼び出し不可能なバージョン。

コンストラクターパラメーターは、 MagicMock と同じ意味を持ちますが、 return_valueside_effect は、呼び出し不可能なモックでは意味がありません。

マジックメソッドは MagicMock オブジェクトでセットアップされるため、それらを構成して通常の方法で使用できます。

>>> mock = MagicMock()
>>> mock[3] = 'fish'
>>> mock.__setitem__.assert_called_with(3, 'fish')
>>> mock.__getitem__.return_value = 'result'
>>> mock[2]
'result'

デフォルトでは、特定のタイプのオブジェクトを返すために、プロトコルメソッドの多くが必要です。 これらのメソッドはデフォルトの戻り値で事前構成されているため、戻り値に関心がない場合は何もしなくても使用できます。 デフォルトを変更したい場合は、戻り値を手動で設定することができます。

メソッドとそのデフォルト:

  • __lt__NotImplemented
  • __gt__NotImplemented
  • __le__NotImplemented
  • __ge__NotImplemented
  • __int__1
  • __contains__False
  • __len__0
  • __iter__iter([])
  • __exit__False
  • __aexit__False
  • __complex__1j
  • __float__1.0
  • __bool__True
  • __index__1
  • __hash__:モックのデフォルトハッシュ
  • __str__:モックのデフォルトstr
  • __sizeof__:モックのデフォルトのsizeof

例えば:

>>> mock = MagicMock()
>>> int(mock)
1
>>> len(mock)
0
>>> list(mock)
[]
>>> object() in mock
False

__eq__()__ne__()の2つの等式メソッドは特別です。 戻り値を変更して別のものを返す場合を除き、 side_effect 属性を使用して、IDのデフォルトの等価比較を実行します。

>>> MagicMock() == 3
False
>>> MagicMock() != 3
True
>>> mock = MagicMock()
>>> mock.__eq__.return_value = True
>>> mock == 3
True

MagicMock.__iter__()の戻り値は、任意の反復可能オブジェクトにすることができ、反復子である必要はありません。

>>> mock = MagicMock()
>>> mock.__iter__.return_value = ['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
['a', 'b', 'c']

戻り値イテレータである場合、それを1回繰り返すと消費され、その後の反復では空のリストになります。

>>> mock.__iter__.return_value = iter(['a', 'b', 'c'])
>>> list(mock)
['a', 'b', 'c']
>>> list(mock)
[]

MagicMockには、サポートされているすべてのマジックメソッドが構成されていますが、一部のあいまいなメソッドと廃止されたメソッドは除きます。 必要に応じて、これらを設定することもできます。

サポートされているがMagicMockでデフォルトでセットアップされていないマジックメソッドは次のとおりです。

  • __subclasses__
  • __dir__
  • __format__
  • __get____set____delete__
  • __reversed__および__missing__
  • __reduce____reduce_ex____getinitargs____getnewargs____getstate____setstate__
  • __getformat__および__setformat__
2
マジックメソッドは、インスタンスではなくクラスで検索する必要があります。 Pythonのバージョンが異なれば、このルールの適用について一貫性がありません。 サポートされているプロトコルメソッドは、サポートされているすべてのバージョンのPythonで機能するはずです。
3
関数は基本的にクラスに接続されていますが、各Mockインスタンスは他のインスタンスから分離されたままになっています。


ヘルパー

歩哨

unittest.mock.sentinel

sentinelオブジェクトは、テストに一意のオブジェクトを提供する便利な方法を提供します。

属性は、名前でアクセスするとオンデマンドで作成されます。 同じ属性にアクセスすると、常に同じオブジェクトが返されます。 返されるオブジェクトには、テストの失敗メッセージが読み取れるように、適切なreprがあります。

バージョン3.7で変更: sentinel属性は、コピーまたはピクルスのときにIDを保持するようになりました。

テストするときに、特定のオブジェクトが引数として別のメソッドに渡されるか、返されるかをテストする必要がある場合があります。 これをテストするために、名前付きセンチネルオブジェクトを作成するのが一般的です。 sentinel は、このようなオブジェクトのIDを作成およびテストするための便利な方法を提供します。

この例では、methodにモンキーパッチを適用してsentinel.some_objectを返します。

>>> real = ProductionClass()
>>> real.method = Mock(name="method")
>>> real.method.return_value = sentinel.some_object
>>> result = real.method()
>>> assert result is sentinel.some_object
>>> sentinel.some_object
sentinel.some_object

ディフォルト

unittest.mock.DEFAULT
DEFAULT オブジェクトは、事前に作成された歩哨(実際にはsentinel.DEFAULT)です。 side_effect 関数で使用して、通常の戻り値を使用する必要があることを示すことができます。


電話

unittest.mock.call(*args, **kwargs)

call()は、 call_argscall_args_listmock_calls 、 method_calls [ X170X]。 call()は、 assert_has_calls()と一緒に使用することもできます。

>>> m = MagicMock(return_value=None)
>>> m(1, 2, a='foo', b='bar')
>>> m()
>>> m.call_args_list == [call(1, 2, a='foo', b='bar'), call()]
True
call.call_list()
複数の呼び出しを表す呼び出しオブジェクトの場合、 call_list()は、すべての中間呼び出しと最終呼び出しのリストを返します。

call_listは、「連鎖呼び出し」でアサーションを作成する場合に特に役立ちます。 連鎖呼び出しは、1行のコードでの複数の呼び出しです。 これにより、モックの mock_calls に複数のエントリが作成されます。 呼び出しのシーケンスを手動で作成するのは面倒な場合があります。

call_list()は、同じ連鎖呼び出しからの呼び出しのシーケンスを構築できます。

>>> m = MagicMock()
>>> m(1).method(arg='foo').other('bar')(2.0)
<MagicMock name='mock().method().other()()' id='...'>
>>> kall = call(1).method(arg='foo').other('bar')(2.0)
>>> kall.call_list()
[call(1),
 call().method(arg='foo'),
 call().method().other('bar'),
 call().method().other()(2.0)]
>>> m.mock_calls == kall.call_list()
True

callオブジェクトは、その構築方法に応じて、(positional args、keyword args)または(name、positional args、keyword args)のタプルになります。 それらを自分で作成する場合、これは特に興味深いものではありませんが、 Mock.call_argsMock.call_args_list 、および Mockにあるcallオブジェクトです。 mock_calls 属性をイントロスペクトして、それらに含まれる個々の引数を取得できます。

Mock.call_argsMock.call_args_listcallオブジェクトは(positional args、keyword args)の2つのタプルですが、callオブジェクトは Mock.mock_calls は、自分で作成したものとともに、(名前、位置引数、キーワード引数)の3つのタプルです。

それらの「タプルネス」を使用して、より複雑な内省とアサーションの個々の引数を引き出すことができます。 位置引数はタプル(位置引数がない場合は空のタプル)であり、キーワード引数は辞書です。

>>> m = MagicMock(return_value=None)
>>> m(1, 2, 3, arg='one', arg2='two')
>>> kall = m.call_args
>>> kall.args
(1, 2, 3)
>>> kall.kwargs
{'arg': 'one', 'arg2': 'two'}
>>> kall.args is kall[0]
True
>>> kall.kwargs is kall[1]
True
>>> m = MagicMock()
>>> m.foo(4, 5, 6, arg='two', arg2='three')
<MagicMock name='mock.foo()' id='...'>
>>> kall = m.mock_calls[0]
>>> name, args, kwargs = kall
>>> name
'foo'
>>> args
(4, 5, 6)
>>> kwargs
{'arg': 'two', 'arg2': 'three'}
>>> name is m.mock_calls[0][0]
True

create_autospec

unittest.mock.create_autospec(spec, spec_set=False, instance=False, **kwargs)

別のオブジェクトをスペックとして使用して、モックオブジェクトを作成します。 モックの属性は、 spec オブジェクトの対応する属性を仕様として使用します。

モックされている関数またはメソッドは、正しい署名で呼び出されていることを確認するために引数がチェックされます。

spec_setTrueの場合、specオブジェクトに存在しない属性を設定しようとすると、 AttributeError が発生します。

クラスが仕様として使用されている場合、モック(クラスのインスタンス)の戻り値は同じ仕様になります。 instance=Trueを渡すことにより、インスタンスオブジェクトの仕様としてクラスを使用できます。 返されたモックは、モックのインスタンスが呼び出し可能である場合にのみ呼び出し可能になります。

create_autospec()は、作成されたモックのコンストラクターに渡される任意のキーワード引数も取ります。

create_autospec()および patch()autospec 引数を使用して自動スペックを使用する方法の例については、 Autospeccing を参照してください。

バージョン3.8で変更: create_autospec()は、ターゲットが非同期関数の場合、 AsyncMock を返すようになりました。


どれか

unittest.mock.ANY

モックの呼び出しで引数の some についてアサーションを作成する必要がある場合がありますが、一部の引数を気にしないか、 call_args から個別に引き出して作成する必要があります。それらに対するより複雑なアサーション。

特定の引数を無視するには、すべてと同等のオブジェクトを渡すことができます。 assert_called_with()および assert_called_once_with()の呼び出しは、何が渡されても成功します。

>>> mock = Mock(return_value=None)
>>> mock('foo', bar=object())
>>> mock.assert_called_once_with('foo', bar=ANY)

ANY は、 mock_calls のようなコールリストとの比較にも使用できます。

>>> m = MagicMock(return_value=None)
>>> m(1)
>>> m(1, 2)
>>> m(object())
>>> m.mock_calls == [call(1), call(1, 2), ANY]
True

FILTER_DIR

unittest.mock.FILTER_DIR

FILTER_DIR は、モックオブジェクトが dir()に応答する方法を制御するモジュールレベルの変数です(Python 2.6以降の場合のみ)。 デフォルトはTrueで、以下で説明するフィルタリングを使用して、有用なメンバーのみを表示します。 このフィルタリングが気に入らない場合、または診断目的でオフにする必要がある場合は、mock.FILTER_DIR = Falseを設定してください。

フィルタリングをオンにすると、dir(some_mock)には有用な属性のみが表示され、通常は表示されない動的に作成された属性が含まれます。 モックが spec (またはもちろん autospec )で作成された場合、まだアクセスされていなくても、オリジナルのすべての属性が表示されます。

>>> dir(Mock())
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 ...
>>> from urllib import request
>>> dir(Mock(spec=request))
['AbstractBasicAuthHandler',
 'AbstractDigestAuthHandler',
 'AbstractHTTPHandler',
 'BaseHandler',
 ...

あまり役に立たない(モックされているものではなく、 Mock 専用)アンダースコアおよびダブルアンダースコアプレフィックス属性の多くは、 dir()を呼び出した結果からフィルタリングされています。 モック。 この動作が気に入らない場合は、モジュールレベルスイッチ FILTER_DIR を設定してオフに切り替えることができます。

>>> from unittest import mock
>>> mock.FILTER_DIR = False
>>> dir(mock.Mock())
['_NonCallableMock__get_return_value',
 '_NonCallableMock__get_side_effect',
 '_NonCallableMock__return_value_doc',
 '_NonCallableMock__set_return_value',
 '_NonCallableMock__set_side_effect',
 '__call__',
 '__class__',
 ...

または、vars(my_mock)(インスタンスメンバー)とdir(type(my_mock))(タイプメンバー)を使用して、mock.FILTER_DIRに関係なくフィルタリングをバイパスすることもできます。


mock_open

unittest.mock.mock_open(mock=None, read_data=None)

open()の使用を置き換えるモックを作成するヘルパー関数。 これは、直接呼び出されるか、コンテキストマネージャーとして使用される open()で機能します。

mock 引数は、構成するモックオブジェクトです。 None(デフォルト)の場合、 MagicMock が作成され、APIは標準のファイルハンドルで使用可能なメソッドまたは属性に制限されます。

read_data は、返されるファイルハンドルのread()readline()、および readlines()メソッドの文字列です。 これらのメソッドを呼び出すと、データがなくなるまで read_data からデータが取得されます。 これらのメソッドのモックはかなり単純です。モックが呼び出されるたびに、 read_data が最初に巻き戻されます。 テストされたコードにフィードするデータをさらに制御する必要がある場合は、このモックを自分でカスタマイズする必要があります。 それでも不十分な場合は、 PyPI のインメモリファイルシステムパッケージの1つで、テスト用の現実的なファイルシステムを提供できます。

バージョン3.4で変更: readline()および readlines()のサポートが追加されました。 read()のモックは、呼び出しごとに返すのではなく、 read_data を消費するように変更されました。

バージョン3.5で変更: read_data は、モックを呼び出すたびにリセットされるようになりました。

バージョン3.8で変更:実装に__iter__()を追加して、反復(forループなど)が read_data を正しく消費するようにしました。

open()をコンテキストマネージャーとして使用することは、ファイルハンドルが適切に閉じられ、一般的になりつつあることを確認するための優れた方法です。

with open('/some/path', 'w') as f:
    f.write('something')

問題は、 open()の呼び出しをモックアウトしたとしても、コンテキストマネージャーとして使用されるのは返されたオブジェクトである(そして__enter__()と[ X159X] が呼び出されました)。

MagicMock を使用してコンテキストマネージャーをモックすることは、ヘルパー関数が役立つほど一般的で面倒です。

>>> m = mock_open()
>>> with patch('__main__.open', m):
...     with open('foo', 'w') as h:
...         h.write('some stuff')
...
>>> m.mock_calls
[call('foo', 'w'),
 call().__enter__(),
 call().write('some stuff'),
 call().__exit__(None, None, None)]
>>> m.assert_called_once_with('foo', 'w')
>>> handle = m()
>>> handle.write.assert_called_once_with('some stuff')

そしてファイルを読むために:

>>> with patch('__main__.open', mock_open(read_data='bibble')) as m:
...     with open('foo') as h:
...         result = h.read()
...
>>> m.assert_called_once_with('foo')
>>> assert result == 'bibble'

自動スペック

自動スペックは、モックの既存のspec機能に基づいています。 モックのAPIを元のオブジェクト(仕様)のAPIに制限しますが、再帰的(遅延実装)であるため、モックの属性は仕様の属性と同じAPIのみを持ちます。 さらに、モックされた関数/メソッドは元の関数/メソッドと同じ呼び出しシグネチャを持っているため、誤って呼び出された場合は TypeError が発生します。

自動スペックがどのように機能するかを説明する前に、それが必要な理由は次のとおりです。

モックは非常に強力で柔軟なオブジェクトですが、テスト対象のシステムからオブジェクトをモックアウトするために使用すると、2つの欠陥があります。 これらの欠陥の1つは、 Mock apiに固有のものであり、もう1つは、モックオブジェクトの使用に関するより一般的な問題です。

まず、モックに固有の問題。 Mock には、非常に便利な2つのassertメソッドがあります。 assert_called_with()assert_called_once_with()です。

>>> mock = Mock(name='Thing', return_value=None)
>>> mock(1, 2, 3)
>>> mock.assert_called_once_with(1, 2, 3)
>>> mock(1, 2, 3)
>>> mock.assert_called_once_with(1, 2, 3)
Traceback (most recent call last):
 ...
AssertionError: Expected 'mock' to be called once. Called 2 times.

モックはオンデマンドで属性を自動作成し、任意の引数で属性を呼び出すことができるため、これらのアサートメソッドのいずれかのスペルを間違えると、アサーションは失われます。

>>> mock = Mock(name='Thing', return_value=None)
>>> mock(1, 2, 3)
>>> mock.assret_called_once_with(4, 5, 6)

タイプミスが原因で、テストがサイレントに誤って合格する可能性があります。

2番目の問題は、モックに対してより一般的です。 コードの一部をリファクタリングしたり、メンバーの名前を変更したりした場合でも、古いAPI を使用しているが、実際のオブジェクトの代わりにモックを使用しているコードのテストはすべて合格します。 これは、コードが壊れていても、テストはすべて合格できることを意味します。

これが、統合テストと単体テストが必要なもう1つの理由であることに注意してください。 すべてを個別にテストすることはすべて問題なく、ダンディですが、ユニットがどのように「相互に接続」されているかをテストしない場合でも、テストで検出された可能性のあるバグの余地がたくさんあります。

mockには、スペックと呼ばれる、これを支援する機能がすでに用意されています。 モックのspecとしてクラスまたはインスタンスを使用する場合、実際のクラスに存在するモックの属性にのみアクセスできます。

>>> from urllib import request
>>> mock = Mock(spec=request.Request)
>>> mock.assret_called_with
Traceback (most recent call last):
 ...
AttributeError: Mock object has no attribute 'assret_called_with'

仕様はモック自体にのみ適用されるため、モックのどのメソッドでも同じ問題が発生します。

>>> mock.has_data()
<mock.Mock object at 0x...>
>>> mock.has_data.assret_called_with()

自動スペックはこの問題を解決します。 autospec=Truepatch() / patch.object()に渡すか、 create_autospec()関数を使用してモックを作成できます。スペック。 patch()に対してautospec=True引数を使用すると、置き換えられるオブジェクトがスペックオブジェクトとして使用されます。 スペックリングは「遅延」で行われるため(スペックはモックの属性にアクセスすると作成されます)、パフォーマンスに大きな影響を与えることなく、非常に複雑なオブジェクトや深くネストされたオブジェクト(モジュールをインポートするモジュールをインポートするモジュールなど)で使用できます。

使用例は次のとおりです。

>>> from urllib import request
>>> patcher = patch('__main__.request', autospec=True)
>>> mock_request = patcher.start()
>>> request is mock_request
True
>>> mock_request.Request
<MagicMock name='request.Request' spec='Request' id='...'>

request.Requestに仕様があることがわかります。 request.Requestは、コンストラクターで2つの引数を取ります(そのうちの1つは self です)。 間違って呼び出そうとすると、次のようになります。

>>> req = request.Request()
Traceback (most recent call last):
 ...
TypeError: <lambda>() takes at least 2 arguments (1 given)

この仕様は、インスタンス化されたクラスにも適用されます(つまり、 特定のモックの戻り値):

>>> req = request.Request('foo')
>>> req
<NonCallableMagicMock name='request.Request()' spec='Request' id='...'>

Requestオブジェクトは呼び出し可能ではないため、モックアウトされたrequest.Requestをインスタンス化した場合の戻り値は呼び出し不可能なモックです。 仕様が整っていると、アサートのタイプミスによって正しいエラーが発生します。

>>> req.add_header('spam', 'eggs')
<MagicMock name='request.Request().add_header()' id='...'>
>>> req.add_header.assret_called_with
Traceback (most recent call last):
 ...
AttributeError: Mock object has no attribute 'assret_called_with'
>>> req.add_header.assert_called_with('spam', 'eggs')

多くの場合、既存の patch()呼び出しにautospec=Trueを追加するだけで、タイプミスやAPIの変更によるバグから保護できます。

autospec から patch()を使用するだけでなく、自動スペックのモックを直接作成するための create_autospec()があります。

>>> from urllib import request
>>> mock_request = create_autospec(request)
>>> mock_request.Request('foo', 'bar')
<NonCallableMagicMock name='mock.Request()' spec='Request' id='...'>

ただし、これには警告と制限がないわけではありません。そのため、デフォルトの動作ではありません。 スペックオブジェクトで使用可能な属性を知るために、autospecはスペックをイントロスペクト(属性にアクセス)する必要があります。 モックの属性をトラバースすると、元のオブジェクトの対応するトラバースが内部で発生します。 指定されたオブジェクトのいずれかに、コードの実行をトリガーできるプロパティまたは記述子がある場合、autospecを使用できない可能性があります。 一方、イントロスペクションが安全になるようにオブジェクトを設計することをお勧めします 4

さらに深刻な問題は、インスタンス属性が__init__()メソッドで作成され、クラスにまったく存在しないことが一般的であるということです。 autospec は動的に作成された属性を認識できず、APIを表示可能な属性に制限します。

>>> class Something:
...   def __init__(self):
...     self.a = 33
...
>>> with patch('__main__.Something', autospec=True):
...   thing = Something()
...   thing.a
...
Traceback (most recent call last):
  ...
AttributeError: Mock object has no attribute 'a'

この問題を解決するには、いくつかの方法があります。 最も簡単ですが、必ずしも最も煩わしいとは限りませんが、作成後にモックに必要な属性を設定するだけです。 autospec では、仕様に存在しない属性をフェッチできないからといって、それらの設定が妨げられることはありません。

>>> with patch('__main__.Something', autospec=True):
...   thing = Something()
...   thing.a = 33
...

specautospec の両方のより積極的なバージョンがあり、存在しない属性の設定を防ぎます。 これは、コードでセットの有効な属性のみを確保したい場合に役立ちますが、明らかにこの特定のシナリオを防ぎます。

>>> with patch('__main__.Something', autospec=True, spec_set=True):
...   thing = Something()
...   thing.a = 33
...
Traceback (most recent call last):
 ...
AttributeError: Mock object has no attribute 'a'

おそらく、問題を解決する最善の方法は、__init__()で初期化されたインスタンスメンバーのデフォルト値としてクラス属性を追加することです。 __init__()でデフォルト属性のみを設定している場合は、クラス属性(もちろんインスタンス間で共有)を介してそれらを提供する方が高速であることに注意してください。 例えば

class Something:
    a = 33

これは別の問題を引き起こします。 後で別のタイプのオブジェクトになるメンバーにデフォルト値Noneを提供することは比較的一般的です。 Noneは、任意の属性またはメソッドにアクセスできないため、仕様としては役に立ちません。 None決して仕様として役立つことはなく、通常は他のタイプのメンバーを示している可能性があるため、autospecは[に設定されているメンバーの仕様を使用しません。 X188X] 。 これらは通常のモックになります(まあ-MagicMocks):

>>> class Something:
...     member = None
...
>>> mock = create_autospec(Something)
>>> mock.member.foo.bar.baz()
<MagicMock name='mock.member.foo.bar.baz()' id='...'>

デフォルトを追加するために本番クラスを変更することがあなたの好みに合わない場合は、より多くのオプションがあります。 これらの1つは、クラスではなくインスタンスを仕様として使用することです。 もう1つは、本番クラスのサブクラスを作成し、本番クラスに影響を与えずにデフォルトをサブクラスに追加することです。 これらは両方とも、仕様として代替オブジェクトを使用する必要があります。 ありがたいことに、 patch()はこれをサポートしています-代替オブジェクトを autospec 引数として渡すだけです。

>>> class Something:
...   def __init__(self):
...     self.a = 33
...
>>> class SomethingForTest(Something):
...   a = 33
...
>>> p = patch('__main__.Something', autospec=SomethingForTest)
>>> mock = p.start()
>>> mock.a
<NonCallableMagicMock name='Something.a' spec='int' id='...'>
4
これは、クラスまたはすでにインスタンス化されているオブジェクトにのみ適用されます。 モッククラスを呼び出してモックインスタンスを作成するは、実際のインスタンスを作成しません。 実行されるのは、属性ルックアップ( dir()の呼び出しとともに)のみです。


シーリングモック

unittest.mock.seal(mock)

シールは、シールされているモックの属性、またはすでに再帰的にモックになっているその属性のいずれかにアクセスするときに、モックの自動作成を無効にします。

名前または仕様を持つモックインスタンスが属性に割り当てられている場合、それはシーリングチェーンでは考慮されません。 これにより、シールがモックオブジェクトの一部を固定するのを防ぐことができます。

>>> mock = Mock()
>>> mock.submock.attribute1 = 2
>>> mock.not_submock = mock.Mock(name="sample_name")
>>> seal(mock)
>>> mock.new_attribute  # This will raise AttributeError.
>>> mock.submock.attribute2  # This will raise AttributeError.
>>> mock.not_submock.attribute2  # This won't raise.

バージョン3.7の新機能。