"unittest.mock" --- 入門
************************

Added in version 3.3.


Mock を使う
===========


モックでメソッドにパッチを当てる
--------------------------------

一般的な "Mock" の使い方の中には次のものがあります:

* メソッドにパッチを当てる

* オブジェクトに対するメソッド呼び出しを記録する

システムの他の部分からメソッドが正しい引数で呼び出されたかどうかを確認
するために、そのオブジェクトのメソッドを置き換えることができます:

>>> real = SomeClass()
>>> real.method = MagicMock(name='method')
>>> real.method(3, 4, 5, key='value')
<MagicMock name='method()' id='...'>

モック(上の例では "real.method")が利用された場合、どう使われたかを
assert できるようにする属性やメソッドがモックにあります。

注釈:

  この例のような場合、たいてい "Mock" と "MagicMock" は互換です。
  "MagicMock" の方が強力なので、デフォルトではこちらを使うといいでしょ
  う。

モックが呼び出されると、その "called" 属性が "True" に設定されます。そ
して "assert_called_with()" や "assert_called_once_with()" メソッドを
使ってそのメソッドが正しい引数で呼び出されたかどうかをチェックできます
。

次の例では "ProductionClass().method" が "something" メソッドを呼び出
したことをテストしています:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)


オブジェクトのメソッド呼び出しにモックを使う
--------------------------------------------

上の例ではオブジェクトのメソッドに対して直接パッチを当てて、それが正し
く呼び出されていたかどうかをテストしていました。もう一つのよくあるユー
スケースが、モックをメソッド (またはテスト対象のシステムのどこか) に渡
して、それが正しく利用されたかどうかをチェックする方法です。

次の例で、"ProductionClass" は "closer" メソッドを持っています。このメ
ソッドは渡されたオブジェクトの "close" メソッドを呼び出します。

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...

ですからこれをテストするには、"close" メソッドを持ったオブジェクトを渡
して、それが正しく呼び出されたかどうかをテストしなければなりません。

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()

モックに *close* メソッドを持たせるために何か準備する必要はありません
。 *close* メソッドにアクセスすると自動的にそれが作られます。なので、
もし *close* が呼び出されなかったとしてもテスト時に生成されるのですが
、 "assert_called_with()" が failure 例外を発生させます。


クラスをモックする
------------------

他のよくあるユースケースが、テスト対象のコードによってインスタンス化さ
れているクラスをモックに置き換えることです。クラスに patch すると、そ
のクラスがモックに置き換えられます。インスタンスは *クラスを呼び出した
時に* 作られます。なので、モックの戻り値を使うことで、「モックのインス
タンス」にアクセスできます。

次の例では、 "some_function" という関数が "Foo" をインスタンス化し、そ
の method を呼び出しています。 "patch()" を呼び出すと "Foo" クラスをモ
ックに置き換えます。 "Foo" のインスタンスはモックを呼び出して作られる
ので、モックの "return_value" を変更することでカスタマイズできます。:

   >>> def some_function():
   ...     instance = module.Foo()
   ...     return instance.method()
   ...
   >>> with patch('module.Foo') as mock:
   ...     instance = mock.return_value
   ...     instance.method.return_value = 'the result'
   ...     result = some_function()
   ...     assert result == 'the result'


モックに名前をつける
--------------------

モックに名前をつけると便利なことがあります。その名前はモックを repr し
たときに表示されるので、モックがテスト失敗のメッセージ内に現れた時に便
利です。また、モックの名前はそのモックの属性やメソッドにも伝播します:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>


すべての呼び出しを追跡する
--------------------------

メソッドの複数回の呼び出しをトラックしたいことがあります。
"mock_calls" 属性は、そのモックの子属性やさらにその子孫に対する呼び出
しすべてを記録しています。

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]

"mock_calls" に対して assert すると、予期していないメソッド呼び出しが
あったときにその assert が失敗します。これはあるメソッド呼び出しが期待
通りに実行されたかどうかだけでなく、その呼び出し順序や期待した以外の呼
び出しが起こらなかったことまでテストできるので便利です:

"mock_calls" と比較するリストを作るために "call" オブジェクトを利用で
きます:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True

ただし、モックを返す呼び出しの引数は、その後の入れ子の呼び出しには記録
されません。 そのため、祖先を作成した呼び出しの引数が重要な場合、その
情報を含めて入れ子の呼び出しを追跡することはできません。

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True


戻り値と属性を設定する
----------------------

モックオブジェクトに戻り値を設定するのはとっても簡単です:

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

もちろん同じことがモックのメソッドに対しても行えます:

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

コンストラクターで戻り値を設定することもできます:

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

モックに属性を設定したかったら、普通に設定するだけです:

>>> mock = Mock()
>>> mock.x = 3
>>> mock.x
3

"mock.connection.cursor().execute("SELECT 1")" のような複雑なケースで
モックを使いたい場合もあります。この呼出があるリストを返すようにしたい
場合、このネストした呼び出しを構成しなければなりません。

"call" を使って "chained call" 内の呼び出しを構成して、 assert で使う
ことができます:

>>> mock = Mock()
>>> cursor = mock.connection.cursor.return_value
>>> cursor.execute.return_value = ['foo']
>>> mock.connection.cursor().execute("SELECT 1")
['foo']
>>> expected = call.connection.cursor().execute("SELECT 1").call_list()
>>> mock.mock_calls
[call.connection.cursor(), call.connection.cursor().execute('SELECT 1')]
>>> mock.mock_calls == expected
True

call object を chained call を表す list にするために ".call_list()" を
使います。


モックから例外を発生させる
--------------------------

"side_effect" という便利な属性があります。この属性に例外クラスやそのイ
ンスタンスを設定すると、モックが呼ばれた時にその例外を発生させます。

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


side_effect の関数と iterable
-----------------------------

"side_effect" には関数や iterable を設定することもできます。
"side_effect" に iterable を設定するユースケースは、そのモックが複数回
呼び出され、そのたびに違う値を返したい場合です。"side_effect" に
iterable を設定すると、そのモックに対するすべての呼び出しは iterable
の次の値を返します:

>>> mock = MagicMock(side_effect=[4, 5, 6])
>>> mock()
4
>>> mock()
5
>>> mock()
6

より高度なユースケースとして、mock が呼び出された時の引数によって戻り
値を変化させたい場合は、"side_effect" に関数を設定することができます。
その関数は mock と同じ引数で呼び出されます。その関数の戻り値がそのモッ
ク呼び出しの戻り値になります:

>>> vals = {(1, 2): 1, (2, 3): 2}
>>> def side_effect(*args):
...     return vals[args]
...
>>> mock = MagicMock(side_effect=side_effect)
>>> mock(1, 2)
1
>>> mock(2, 3)
2


非同期イテレータをモックする
----------------------------

Python 3.8以降、"AsyncMock" と "MagicMock" は "__aiter__" を通じて 非
同期イテレータ (Asynchronous Iterator) のモックをサポートしています。
"__aiter__" の "return_value" 属性はイテレーションに使用される戻り値を
設定するために使用できます。

>>> mock = MagicMock()  # AsyncMock also works here
>>> mock.__aiter__.return_value = [1, 2, 3]
>>> async def main():
...     return [i async for i in mock]
...
>>> asyncio.run(main())
[1, 2, 3]


非同期コンテキストマネージャをモックする
----------------------------------------

Python 3.8以降、"AsyncMock" と "MagicMock" は "__aenter__" と
"__aexit__" を通じて 非同期コンテキストマネージャ (Asynchronous
Context Manager) のモックをサポートしています。デフォルトでは、
"__aenter__" と "__aexit__" は非同期関数を返す "AsyncMock" インスタン
スです。

>>> class AsyncContextManager:
...     async def __aenter__(self):
...         return self
...     async def __aexit__(self, exc_type, exc, tb):
...         pass
...
>>> mock_instance = MagicMock(AsyncContextManager())  # AsyncMock also works here
>>> async def main():
...     async with mock_instance as result:
...         pass
...
>>> asyncio.run(main())
>>> mock_instance.__aenter__.assert_awaited_once()
>>> mock_instance.__aexit__.assert_awaited_once()


既存のオブジェクトからモックを作る
----------------------------------

mock を使いすぎることの問題の一つは、テストが実際のコードではなく mock
の実装をテストするようになってしまうことです。"some_method" というメソ
ッドを実装したクラスがあるとします。他のクラスをテストするときに、
"some_method" を提供する mock を使います。最初のクラスをリファクタリン
グして "some_method" がなくなった時、コードは壊れているのにテストは通
る状態になってしまいます

"Mock" は *spec* というキーワード引数で mock の定義となるオブジェクト
を指定できます。定義オブジェクトに存在しないメソッドや属性にアクセスす
ると AttributeError を発生させます。定義となるクラスの実装を変更した場
合、テストの中でそのクラスをインスタンス化させなくても、テストを失敗さ
せる事ができます。

>>> mock = Mock(spec=SomeClass)
>>> mock.old_method()
Traceback (most recent call last):
   ...
AttributeError: Mock object has no attribute 'old_method'. Did you mean: 'class_method'?

spec を指定すると、モックへの呼び出しをより柔軟に照合でき、引数が位置
引数として渡されたか、名前を指定して渡されたかを問いません。

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

このよりスマートなマッチングをモックのメソッド呼び出しにも適用したい場
合は、auto-speccing を使用します。

任意の属性の参照だけでなく代入も禁止するより強い定義を利用したい場合は
、*spec* の代わりに *spec_set* を使います。


side_effect でファイルごとに異なる内容を返す
--------------------------------------------

"mock_open()" は "open()" にパッチを適用するために使います。
"side_effect" を使うと、呼び出しのたびに新しい Mock オブジェクトを返せ
ます。 これを利用して、辞書に保存した異なる内容をファイルごとに返せま
す。

   DEFAULT = "default"
   data_dict = {"file1": "data1",
                "file2": "data2"}

   def open_side_effect(name):
       return mock_open(read_data=data_dict.get(name, DEFAULT))()

   with patch("builtins.open", side_effect=open_side_effect):
       with open("file1") as file1:
           assert file1.read() == "data1"

       with open("file2") as file2:
           assert file2.read() == "data2"

       with open("file3") as file2:
           assert file2.read() == "default"


patch デコレータ
================

注釈:

  "patch()" では探索される名前空間内のオブジェクトにパッチをあてること
  が重要です。通常は単純ですが、クイックガイドには どこにパッチするか
  を読んでください。

テストの中でクラス属性やモジュール属性、例えば組み込み関数や、テスト対
象モジュールにあるインスタンス化されるクラスに対してパッチしたいことが
あります。モジュールやクラスは実際はグローバルなので、パッチするときは
必ずテスト後にパッチを解除しないと、そのパッチが永続化されて他のテスト
に影響を与え、解析しにくい問題になります。

mock はこのために3つの便利なデコレータを提供しています: "patch()",
"patch.object()", "patch.dict()" です。"patch" はパッチ対象を指定する
"package.module.Class.attribute" の形式の文字列を引数に取ります。オプ
ションでその属性 (やクラスなど) を置き換えるオブジェクトを渡すことがで
きます。 'patch.object' はオブジェクトとパッチしたい属性名、それにオプ
ションで置き換えるオブジェクトを受け取ります。

"patch.object":

   >>> original = SomeClass.attribute
   >>> @patch.object(SomeClass, 'attribute', sentinel.attribute)
   ... def test():
   ...     assert SomeClass.attribute == sentinel.attribute
   ...
   >>> test()
   >>> assert SomeClass.attribute == original

   >>> @patch('package.module.attribute', sentinel.attribute)
   ... def test():
   ...     from package.module import attribute
   ...     assert attribute is sentinel.attribute
   ...
   >>> test()

モジュール ("builtins" を含む) をパッチしようとする場合、
"patch.object()" の代わりに "patch()" を使用してください:

>>> mock = MagicMock(return_value=sentinel.file_handle)
>>> with patch('builtins.open', mock):
...     handle = open('filename', 'r')
...
>>> mock.assert_called_with('filename', 'r')
>>> assert handle == sentinel.file_handle, "incorrect file handle returned"

モジュール名は必要に応じて "package.module" のようにドットを含むことが
できます:

   >>> @patch('package.module.ClassName.attribute', sentinel.attribute)
   ... def test():
   ...     from package.module import ClassName
   ...     assert ClassName.attribute == sentinel.attribute
   ...
   >>> test()

テストメソッド自体をデコレートするのは良いパターンです:

>>> class MyTest(unittest.TestCase):
...     @patch.object(SomeClass, 'attribute', sentinel.attribute)
...     def test_something(self):
...         self.assertEqual(SomeClass.attribute, sentinel.attribute)
...
>>> original = SomeClass.attribute
>>> MyTest('test_something').test_something()
>>> assert SomeClass.attribute == original

Mock を使ってパッチしたい場合は、 "patch()" を1引数で (または
"patch.object()" を2引数で) 使うことができます。mock が自動で生成され
、テスト関数/メソッドに渡されます:

>>> class MyTest(unittest.TestCase):
...     @patch.object(SomeClass, 'static_method')
...     def test_something(self, mock_method):
...         SomeClass.static_method()
...         mock_method.assert_called_with()
...
>>> MyTest('test_something').test_something()

次のパターンのように patch デコレータを重ねることができます:

   >>> class MyTest(unittest.TestCase):
   ...     @patch('package.module.ClassName1')
   ...     @patch('package.module.ClassName2')
   ...     def test_something(self, MockClass2, MockClass1):
   ...         self.assertIs(package.module.ClassName1, MockClass1)
   ...         self.assertIs(package.module.ClassName2, MockClass2)
   ...
   >>> MyTest('test_something').test_something()

patch デコレータをネストした際、モックは (デコレータを適用する
*Python* の通常の) 順に適用されます。つまり引数は下から上の順になり、
よって上記の例では "test_module.ClassName2" が先になります。

また、 "patch.dict()" を使うと、スコープ内だけで辞書に値を設定し、テス
ト終了時には元の状態に復元されます:

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

"patch", "patch.object", "patch.dict" は全てコンテキストマネージャーと
しても利用できます。

"patch()" に mock を生成させる場合、その参照を with 文の as を使って受
け取れます:

>>> class ProductionClass:
...     def method(self):
...         pass
...
>>> with patch.object(ProductionClass, 'method') as mock_method:
...     mock_method.return_value = None
...     real = ProductionClass()
...     real.method(1, 2, 3)
...
>>> mock_method.assert_called_with(1, 2, 3)

他の方法として、"patch", "patch.object", "patch.dict" はクラスデコレー
タとしても利用できます。その場合、"test" で始まる全てのメソッドにデコ
レータを適用するのと同じになります。


さらに詳しい例
==============

より高度なシナリオを想定した例をあげていきます。


chained call をモックする
-------------------------

chained call を mock するのは、一度 "return_value" 属性を理解してしま
えば簡単です。mock が最初に呼ばれた時や、呼び出される前に
"return_value" を参照した場合、新しい "Mock" が生成されます。

つまり、戻り値のオブジェクトがどう利用されたかは、"return_value" mock
を調べれば分かります:

>>> mock = Mock()
>>> mock().foo(a=2, b=3)
<Mock name='mock().foo()' id='...'>
>>> mock.return_value.foo.assert_called_with(a=2, b=3)

これをもとに、mock を構成して chained call に対する assert を行うのは
簡単です。もちろん、元のコードを最初からもっとテストしやすく書くという
選択肢もありますが...

では、例として次のようなコードがあるとします:

>>> class Something:
...     def __init__(self):
...         self.backend = BackendProvider()
...     def method(self):
...         response = self.backend.get_endpoint('foobar').create_call('spam', 'eggs').start_call()
...         # more code

"BackendProvider" はすでに十分テストされているとします。"method()" を
どうテストしましょうか？特に、response オブジェクトを使う "# more
code" の部分のコードをテストしたいとします。

この chained call はインスタンス属性を起点にしているので、 "Something"
インスタンスの "backend" 属性に対してモンキーパッチすることができます
。今回の場合だと、最後の "start_call" の呼び出しが返す値にだけ興味があ
るので、あまり多くの構成は必要ありません。このメソッドが返すのが
'file-like' オブジェクトだとしましょう。そうすると、 response オブジェ
クトは組み込みの "open()" を "spec" として利用できます。

これをするために、backend のモックとしてモックインスタンスを作成し、そ
れに対するモックの response オブジェクトを作成します。最終的な
"start_call" の返り値として response をセットすると、このようにするこ
とができます:

   mock_backend.get_endpoint.return_value.create_call.return_value.start_call.return_value = mock_response

これより少し良いやり方として、返り値を直接セットする
"configure_mock()" メソッドを使用して次のようにすることができます:

   >>> something = Something()
   >>> mock_response = Mock(spec=open)
   >>> mock_backend = Mock()
   >>> config = {'get_endpoint.return_value.create_call.return_value.start_call.return_value': mock_response}
   >>> mock_backend.configure_mock(**config)

これらによって「モックの backend」をその場で monkey patch して、実際の
呼び出しを行うことができます:

   >>> something.backend = mock_backend
   >>> something.method()

"mock_calls" を使用すると、チェーンされた呼び出しを単一のアサーション
でチェックすることができます。チェーンされた呼び出しは、1行のコードの
中で行われる複数の呼び出しです。したがって、 "mock_calls" には複数のエ
ントリーがあるでしょう。 "call.call_list()" を使用することで、この呼び
出しのリストを作成することができます:

   >>> chained = call.get_endpoint('foobar').create_call('spam', 'eggs').start_call()
   >>> call_list = chained.call_list()
   >>> assert mock_backend.mock_calls == call_list


部分的なモック
--------------

テストによっては、"datetime.date.today()" をモックに置き換えて決まった
日付を返すようにしつつ、 テスト対象のコードでは新しい日付オブジェクト
を作成できるようにしたい場合があります。 しかし、"datetime.date" は C
で実装されているため、静的メソッド "datetime.date.today()" を単純にモ
ンキーパッチすることはできません。

代わりに、date クラスをモックでラップし、コンストラクタの呼び出しは本
物のクラスに渡す (本物のインスタンスを返す) 方法が使えます。

ここで、テスト対象のモジュール中の "date" クラスをモックするために
"patch decorator" が使用されています。そして、モックの date クラスの
"side_effect" 属性は、本物の date を返すラムダ関数にセットされます。モ
ックの date クラスが呼ばれる時、 "side_effect" によって本物の date が
構築されて返されます。:

   >>> import datetime as dt
   >>> with patch('mymodule.date') as mock_date:
   ...     mock_date.today.return_value = dt.date(2010, 10, 8)
   ...     mock_date.side_effect = lambda *args, **kw: dt.date(*args, **kw)
   ...
   ...     assert mymodule.date.today() == dt.date(2010, 10, 8)
   ...     assert mymodule.date(2009, 6, 8) == dt.date(2009, 6, 8)

グローバルに "datetime.date" にパッチするのではなく、それを使用するモ
ジュールの中の "date" にパッチしていることに留意してください。どこにパ
ッチするか を参照してください。

When "date.today()" is called a known date is returned, but calls to
the "date(...)" constructor still return normal dates. Without this
you can find yourself having to calculate an expected result using
exactly the same algorithm as the code under test, which is a classic
testing anti-pattern.

dateコンストラクタの呼び出しは、"mock_date" の属性("call_count" とその
仲間)に記録され、テストに役立つこともあります。

日付や他の組み込みクラスのモックに対処する別の方法は このブログエント
リ.で議論されています。


ジェネレータメソッドをモックする
--------------------------------

Pythonのジェネレータは、反復処理された時に一連の値を返す "yield" 文を
使用した関数やメソッドです [1]。

ジェネレータメソッド/関数はジェネレータオブジェクトを返すために呼び出
されます。そしてこのジェネレータオブジェクトが反復処理されます。イテレ
ーションのためのプロトコルメソッドは "__iter__()" なので、"MagicMock"
を使ってこれをモックすることができます。

ここでは"iter"メソッドをジェネレータとして実装したクラスの例を紹介しま
す:

>>> class Foo:
...     def iter(self):
...         for i in [1, 2, 3]:
...             yield i
...
>>> foo = Foo()
>>> list(foo.iter())
[1, 2, 3]

このクラス、特に "iter"メソッドをどのようにモックするのでしょうか。

("list" の呼び出しの中での暗黙的な)イテレーションから返される値を設定
するには、"foo.iter()" の呼び出しで返されるオブジェクトを設定する必要
がある。

>>> mock_foo = MagicMock()
>>> mock_foo.iter.return_value = iter([1, 2, 3])
>>> list(mock_foo.iter())
[1, 2, 3]

[1] ジェネレータ式やジェネレータのより 高度な使い方 もありますが、ここ
    ではそれらについては触れません。ジェネレータとその強力さについての
    非常に良い紹介記事があります: Generator Tricks for Systems
    Programmers。


同じパッチを全てのメソッドに適用する
------------------------------------

複数のテストメソッドに複数のパッチを適用するには、各メソッドに patch
デコレータを付ける方法が考えられますが、同じ記述を繰り返すことになりま
す。 代わりに "patch()" (およびその各種の形式) をクラスデコレータとし
て使えます。 これにより、クラス内のすべてのテストメソッドにパッチを適
用します。 名前が "test" で始まるメソッドをテストメソッドとみなします
。

   >>> @patch('mymodule.SomeClass')
   ... class MyTest(unittest.TestCase):
   ...
   ...     def test_one(self, MockSomeClass):
   ...         self.assertIs(mymodule.SomeClass, MockSomeClass)
   ...
   ...     def test_two(self, MockSomeClass):
   ...         self.assertIs(mymodule.SomeClass, MockSomeClass)
   ...
   ...     def not_a_test(self):
   ...         return 'something'
   ...
   >>> MyTest('test_one').test_one()
   >>> MyTest('test_two').test_two()
   >>> MyTest('test_two').not_a_test()
   'something'

パッチを管理する別の方法として patch のメソッド: start と stop も使え
ます。 これらを使うと、パッチを適用・解除する処理を "setUp" メソッドと
"tearDown" メソッドに移せます。

   >>> class MyTest(unittest.TestCase):
   ...     def setUp(self):
   ...         self.patcher = patch('mymodule.foo')
   ...         self.mock_foo = self.patcher.start()
   ...
   ...     def test_foo(self):
   ...         self.assertIs(mymodule.foo, self.mock_foo)
   ...
   ...     def tearDown(self):
   ...         self.patcher.stop()
   ...
   >>> MyTest('test_foo').run()

この方式を使う場合、必ず "stop" メソッドを呼び出してパッチが解除する必
要があります。setUp の中で例外が発生した場合 tearDown が呼び出されない
ので、これは意外に面倒です。 "unittest.TestCase.addCleanup()" を使うと
簡単にできます:

   >>> class MyTest(unittest.TestCase):
   ...     def setUp(self):
   ...         patcher = patch('mymodule.foo')
   ...         self.addCleanup(patcher.stop)
   ...         self.mock_foo = patcher.start()
   ...
   ...     def test_foo(self):
   ...         self.assertIs(mymodule.foo, self.mock_foo)
   ...
   >>> MyTest('test_foo').run()


束縛されていないメソッドをモックする
------------------------------------

テストでは、*束縛されていないメソッド* にパッチを適用したいことがあり
ます。 つまり、インスタンス上ではなくクラス上のメソッドにパッチを適用
します。 どのオブジェクトがそのメソッドを呼び出したかをアサートするに
は、最初の引数として "self" を渡す必要があります。 ところが、束縛され
ていないメソッドをモックに置き換えると、インスタンスから取得しても束縛
されたメソッドにならず、"self" が渡されません。 このため、モックでその
まま置き換えることはできません。 回避策は、本物の関数に置き換えること
です。 "patch()" デコレータを使えばメソッドを簡単にモックに置き換えら
れるだけに、本物の関数を作成する手間は煩わしく感じられます。

patch に "autospec=True" を渡すと、*本物の* 関数オブジェクトで置き換え
ます。 この関数オブジェクトは置換対象と同じシグネチャを持ちますが、内
部ではモックに処理を委譲します。 これまでと同じようにモックは自動的に
作成されます。 ただし、クラス上の束縛されていないメソッドをこの方法で
置き換えると、 置き換えた関数をインスタンスから取得したときに束縛され
たメソッドになります。 そのため、必要としていたとおりに、最初の引数と
して "self" が渡されます。

>>> class Foo:
...   def foo(self):
...     pass
...
>>> with patch.object(Foo, 'foo', autospec=True) as mock_foo:
...   mock_foo.return_value = 'foo'
...   foo = Foo()
...   foo.foo()
...
'foo'
>>> mock_foo.assert_called_once_with(foo)

"autospec=True" を使用しない場合、束縛されていないメソッドは代わりに
Mockインスタンスでパッチされ、"self" で呼び出されることはありません。


モックで複数回の呼び出しをチェックする
--------------------------------------

モックには、モックオブジェクトがどのように使用されるかをアサートするた
めの素晴らしいAPIがあります。

>>> mock = Mock()
>>> mock.foo_bar.return_value = None
>>> mock.foo_bar('baz', spam='eggs')
>>> mock.foo_bar.assert_called_with('baz', spam='eggs')

モックが一度だけ呼び出されるなら、"assert_called_once_with()" メソッド
を使えます。 このメソッドは "call_count" が 1 であることもアサートしま
す。

>>> mock.foo_bar.assert_called_once_with('baz', spam='eggs')
>>> mock.foo_bar()
>>> mock.foo_bar.assert_called_once_with('baz', spam='eggs')
Traceback (most recent call last):
    ...
AssertionError: Expected 'foo_bar' to be called once. Called 2 times.
Calls: [call('baz', spam='eggs'), call()].

Both "assert_called_with" and "assert_called_once_with" make
assertions about the *most recent* call. If your mock is going to be
called several times, and you want to make assertions about *all*
those calls you can use "call_args_list":

>>> mock = Mock(return_value=None)
>>> mock(1, 2, 3)
>>> mock(4, 5, 6)
>>> mock()
>>> mock.call_args_list
[call(1, 2, 3), call(4, 5, 6), call()]

"call" ヘルパーを使えば、これらの呼び出しについて簡単にアサートするこ
とができます。予想される呼び出しのリストを作成し、それを
"call_args_list" と比較することができます。これは "call_args_list" の
reprと驚くほど似ています:

>>> expected = [call(1, 2, 3), call(4, 5, 6), call()]
>>> mock.call_args_list == expected
True


ミュータブルな引数に対処する
----------------------------

稀ではありますが、問題となることがあるのはミュータブルな引数でモックが
呼び出された場合です。"call_args" や "call_args_list" は引数への*参照*
を保存します。もしテスト対象のコードによって引数が変更されてしまうと、
モックが呼び出された時の値をアサートすることはできなくなります。

この問題を示すコード例を見てみましょう。 次の関数が「mymodule」に定義
されているとします。

   def frob(val):
       pass

   def grob(val):
       "まず frob を呼び出し、その後 val を空にする。"
       frob(val)
       val.clear()

"grob" が "frob" を正しい引数で呼び出していることをテストしようとする
と何が起こるか見てみましょう:

   >>> with patch('mymodule.frob') as mock_frob:
   ...     val = {6}
   ...     mymodule.grob(val)
   ...
   >>> val
   set()
   >>> mock_frob.assert_called_with({6})
   Traceback (most recent call last):
       ...
   AssertionError: Expected: (({6},), {})
   Called with: ((set(),), {})

一つの選択肢は、あなたが渡す引数をモックがコピーすることです。この方法
は、オブジェクトidの同一性に依存したアサーションを行う場合に問題を引き
起こす可能性があります。

"side_effect" を使う解決策があります。 モックに "side_effect" 関数を指
定すると、その関数はモックと同じ引数で呼び出されます。 そこで引数をコ
ピーして保存し、後でアサートできます。 この例では、モックのメソッドで
アサートできるように、*別の* モックで引数を保存します。 ここでもヘルパ
ー関数を使って準備します。

   >>> from copy import deepcopy
   >>> from unittest.mock import Mock, patch, DEFAULT
   >>> def copy_call_args(mock):
   ...     new_mock = Mock()
   ...     def side_effect(*args, **kwargs):
   ...         args = deepcopy(args)
   ...         kwargs = deepcopy(kwargs)
   ...         new_mock(*args, **kwargs)
   ...         return DEFAULT
   ...     mock.side_effect = side_effect
   ...     return new_mock
   ...
   >>> with patch('mymodule.frob') as mock_frob:
   ...     new_mock = copy_call_args(mock_frob)
   ...     val = {6}
   ...     mymodule.grob(val)
   ...
   >>> new_mock.assert_called_with({6})
   >>> new_mock.call_args
   call({6})

"copy_call_args" は、テストで呼び出されるモックとともに呼び出されます
。この関数はアサーションで使用するための新しいモックを返します。
"side_effect" 関数は引数のコピーを作成し、そのコピーを使って
"new_mock" を呼び出します。

注釈:

  もしモックが一度しか使われないのであれば、呼び出された時点で引数をチ
  ェックする簡単な方法があります。単純に "side_effect" 関数の中でチェ
  ックを行えばいいのです。

  >>> def side_effect(arg):
  ...     assert arg == {6}
  ...
  >>> mock = Mock(side_effect=side_effect)
  >>> mock({6})
  >>> mock(set())
  Traceback (most recent call last):
      ...
  AssertionError

別の方法としては、（ "copy.deepcopy()" を使用して）引数をコピーする、
"Mock" や "MagicMock" のサブクラスを作成する方法があります。以下に実装
例を示します。

>>> from copy import deepcopy
>>> class CopyingMock(MagicMock):
...     def __call__(self, /, *args, **kwargs):
...         args = deepcopy(args)
...         kwargs = deepcopy(kwargs)
...         return super().__call__(*args, **kwargs)
...
>>> c = CopyingMock(return_value=None)
>>> arg = set()
>>> c(arg)
>>> arg.add(1)
>>> c.assert_called_with(set())
>>> c.assert_called_with(arg)
Traceback (most recent call last):
    ...
AssertionError: expected call not found.
Expected: mock({1})
Actual: mock(set())
>>> c.foo
<CopyingMock name='mock.foo' id='...'>

"Mock" または "MagicMock" をサブクラス化すると、動的に作成されるすべて
の属性と "return_value" に、自動的にそのサブクラスが使われます。 従っ
て、"CopyingMock" の子モックもすべて "CopyingMock" 型になります。


パッチの入れ子
--------------

patch をコンテキストマネージャとして使うと便利ですが、複数のパッチを適
用すると with 文が入れ子になり、インデントが次第に深くなります。

   >>> class MyTest(unittest.TestCase):
   ...
   ...     def test_foo(self):
   ...         with patch('mymodule.Foo') as mock_foo:
   ...             with patch('mymodule.Bar') as mock_bar:
   ...                 with patch('mymodule.Spam') as mock_spam:
   ...                     assert mymodule.Foo is mock_foo
   ...                     assert mymodule.Bar is mock_bar
   ...                     assert mymodule.Spam is mock_spam
   ...
   >>> original = mymodule.Foo
   >>> MyTest('test_foo').test_foo()
   >>> assert mymodule.Foo is original

unittest の "cleanup" 関数と patch のメソッド: start と stop を使うと
、インデントを入れ子にせず同じことを実現できます。 単純なヘルパーメソ
ッド "create_patch" で、パッチを適用して作成したモックを返します。

   >>> class MyTest(unittest.TestCase):
   ...
   ...     def create_patch(self, name):
   ...         patcher = patch(name)
   ...         thing = patcher.start()
   ...         self.addCleanup(patcher.stop)
   ...         return thing
   ...
   ...     def test_foo(self):
   ...         mock_foo = self.create_patch('mymodule.Foo')
   ...         mock_bar = self.create_patch('mymodule.Bar')
   ...         mock_spam = self.create_patch('mymodule.Spam')
   ...
   ...         assert mymodule.Foo is mock_foo
   ...         assert mymodule.Bar is mock_bar
   ...         assert mymodule.Spam is mock_spam
   ...
   >>> original = mymodule.Foo
   >>> MyTest('test_foo').run()
   >>> assert mymodule.Foo is original


MagicMock で辞書をモックする
----------------------------

辞書や他のコンテナをモックに置き換え、辞書としての振る舞いを保ちながら
、すべてのアクセスを記録したい場合があります。

"MagicMock" を辞書のように振る舞わせ、"side_effect" で辞書へのアクセス
を、自分で管理する本物の辞書に委譲すると実現できます。

"MagicMock" の "__getitem__()" メソッドや "__setitem__()" メソッドが呼
び出されると (通常の辞書アクセス)、 "side_effect" にキーが渡されます
("__setitem__" の場合は値も渡されます)。 戻り値も制御できます。

"MagicMock" を使った後、"call_args_list" などの属性で、辞書がどう使わ
れたかをアサートできます。

>>> my_dict = {'a': 1, 'b': 2, 'c': 3}
>>> def getitem(name):
...      return my_dict[name]
...
>>> def setitem(name, val):
...     my_dict[name] = val
...
>>> mock = MagicMock()
>>> mock.__getitem__.side_effect = getitem
>>> mock.__setitem__.side_effect = setitem

注釈:

  "MagicMock" の代わりに "Mock" を使い、必要な特殊メソッド *だけ* を用
  意することもできます。

  >>> mock = Mock()
  >>> mock.__getitem__ = Mock(side_effect=getitem)
  >>> mock.__setitem__ = Mock(side_effect=setitem)

  *3 つ目* の方法は、"MagicMock" の *spec* (または *spec_set*) 引数に
  "dict" を渡すことです。 これにより、作成した "MagicMock" で使える特
  殊メソッドを辞書のものだけに制限できます。

  >>> mock = MagicMock(spec_set=dict)
  >>> mock.__getitem__.side_effect = getitem
  >>> mock.__setitem__.side_effect = setitem

これらの side_effect 関数を設定すると、"mock" は通常の辞書のように振る
舞いながらアクセスを記録します。 存在しないキーにアクセスしようとする
と、"KeyError" も送出します。

>>> mock['a']
1
>>> mock['c']
3
>>> mock['d']
Traceback (most recent call last):
    ...
KeyError: 'd'
>>> mock['b'] = 'fish'
>>> mock['d'] = 'eggs'
>>> mock['b']
'fish'
>>> mock['d']
'eggs'

使用後は、通常のモックのメソッドと属性を使ってアクセスをアサートできま
す。

>>> mock.__getitem__.call_args_list
[call('a'), call('c'), call('d'), call('b'), call('d')]
>>> mock.__setitem__.call_args_list
[call('b', 'fish'), call('d', 'eggs')]
>>> my_dict
{'a': 1, 'b': 'fish', 'c': 3, 'd': 'eggs'}


Mock のサブクラスと属性
-----------------------

"Mock" をサブクラス化したい理由はいろいろあります。 例えばヘルパーメソ
ッドを追加するためです。 単純な例を見てみましょう。

>>> class MyMock(MagicMock):
...     def has_been_called(self):
...         return self.called
...
>>> mymock = MyMock(return_value=None)
>>> mymock
<MyMock id='...'>
>>> mymock.has_been_called()
False
>>> mymock()
>>> mymock.has_been_called()
True

"Mock" インスタンスの標準的な振る舞いでは、属性と戻り値のモックは、そ
れらにアクセスした元のモックと同じ型になります。 このため、"Mock" の属
性は "Mock"、"MagicMock" の属性は "MagicMock" になります [2]。 従って
、サブクラス化してヘルパーメソッドを追加すると、 そのサブクラスのイン
スタンスの属性や戻り値のモックでもヘルパーメソッドを使えます。

>>> mymock.foo
<MyMock name='mock.foo' id='...'>
>>> mymock.foo.has_been_called()
False
>>> mymock.foo()
<MyMock name='mock.foo()' id='...'>
>>> mymock.foo.has_been_called()
True

これが不便な場合もあります。 例えば、ある利用者 は、モックをサブクラス
化して Twisted アダプター を作成しています。 そのサブクラスが属性にも
使われると、エラーが起きてしまいます。

"Mock" (およびその各種のクラス) は、属性や戻り値の「子モック」を作成す
るために "_get_child_mock" メソッドを使います。 このメソッドをオーバー
ライドすると、属性に自分のサブクラスが使われるのを防げます。 シグネチ
ャは任意のキーワード引数 ("**kwargs") を受け取り、それらをモックのコン
ストラクタに渡す形です。

>>> class Subclass(MagicMock):
...     def _get_child_mock(self, /, **kwargs):
...         return MagicMock(**kwargs)
...
>>> mymock = Subclass()
>>> mymock.foo
<MagicMock name='mock.foo' id='...'>
>>> assert isinstance(mymock, Subclass)
>>> assert not isinstance(mymock.foo, Subclass)
>>> assert not isinstance(mymock(), Subclass)

[2] この規則の例外は、呼び出し不可能なモックです。 属性には呼び出し可
    能なクラスを使います。 そうしないと、呼び出し不可能なモックに呼び
    出し可能なメソッドを持たせられないためです。


patch.dict で import をモックする
---------------------------------

モックへの置き換えが難しくなる状況の 1 つが、関数内でローカルにインポ
ートしている場合です。 パッチで置き換えられるモジュールの名前空間のオ
ブジェクトを使っていないため、置き換えにくくなります。

一般に、ローカルなインポートは避ける方がよいでしょう。 循環依存を防ぐ
ために使われることもありますが、*通常は* コードをリファクタリングする
という、もっとよい解決策があります。 また、インポートを遅らせて「初期
コスト」を避けるために使われることもあります。 これも無条件のローカル
なインポートよりよい方法で解決できます (モジュールをクラスやモジュール
の属性に保存し、最初に使うときだけインポートします)。

その点はさておき、"mock" を使ってインポートの結果を変える方法がありま
す。 インポートは "sys.modules" 辞書から *オブジェクト* を取得します。
取得するのは *オブジェクト* であって、モジュールとは限りません。 モジ
ュールを初めてインポートするとモジュールオブジェクトが "sys.modules"
に格納されるため、通常はインポートするとモジュールが得られます。 しか
し、必ずしもそうである必要はありません。

つまり、"patch.dict()" を使って "sys.modules" に *一時的に* モックを配
置できます。 パッチが有効な間にそのモジュールをインポートすると、モッ
クが取得されます。 パッチが終了すると (デコレートした関数が終了する、
with 文の本体が完了する、または "patcher.stop()" が呼ばれると)、以前の
内容が安全に復元されます。

「fooble」モジュールをモックに置き換える例です。

>>> import sys
>>> mock = Mock()
>>> with patch.dict('sys.modules', {'fooble': mock}):
...    import fooble
...    fooble.blob()
...
<Mock name='mock.blob()' id='...'>
>>> assert 'fooble' not in sys.modules
>>> mock.blob.assert_called_once_with()

このように "import fooble" は成功しますが、終了時には "sys.modules" に
「fooble」は残っていません。

"from module import name" の形式でも同じように動作します。

>>> mock = Mock()
>>> with patch.dict('sys.modules', {'fooble': mock}):
...    from fooble import blob
...    blob.blip()
...
<Mock name='mock.blob.blip()' id='...'>
>>> mock.blob.blip.assert_called_once_with()

少し手を加えると、パッケージのインポートもモックに置き換えられます。

>>> mock = Mock()
>>> modules = {'package': mock, 'package.module': mock.module}
>>> with patch.dict('sys.modules', modules):
...    from package.module import fooble
...    fooble()
...
<Mock name='mock.module.fooble()' id='...'>
>>> mock.module.fooble.assert_called_once_with()


呼び出し順序の追跡と簡潔な呼び出しのアサート
--------------------------------------------

"Mock" クラスでは、"method_calls" 属性でモックオブジェクトのメソッドの
呼び出し *順序* を追跡できます。 これでは別々のモックオブジェクト間の
呼び出し順序を追跡できませんが、"mock_calls" を使うと同じことを実現で
きます。

モックは子モックへの呼び出しを "mock_calls" に記録し、任意の属性にアク
セスすると子モックを作成します。 そこで、1 つの親モックから個々のモッ
クを作成できます。 子モックへの呼び出しはすべて、親の "mock_calls" に
順に記録されます。

>>> manager = Mock()
>>> mock_foo = manager.foo
>>> mock_bar = manager.bar

>>> mock_foo.something()
<Mock name='mock.foo.something()' id='...'>
>>> mock_bar.other.thing()
<Mock name='mock.bar.other.thing()' id='...'>

>>> manager.mock_calls
[call.foo.something(), call.bar.other.thing()]

管理用モックの "mock_calls" 属性と比較することで、順序を含めて呼び出し
をアサートできます。

>>> expected_calls = [call.foo.something(), call.bar.other.thing()]
>>> manager.mock_calls == expected_calls
True

"patch" でモックを作成して配置する場合は、"attach_mock()" メソッドで管
理用モックに取り付けられます。 取り付けた後の呼び出しは、管理用モック
の "mock_calls" に記録されます。

   >>> manager = MagicMock()
   >>> with patch('mymodule.Class1') as MockClass1:
   ...     with patch('mymodule.Class2') as MockClass2:
   ...         manager.attach_mock(MockClass1, 'MockClass1')
   ...         manager.attach_mock(MockClass2, 'MockClass2')
   ...         MockClass1().foo()
   ...         MockClass2().bar()
   <MagicMock name='mock.MockClass1().foo()' id='...'>
   <MagicMock name='mock.MockClass2().bar()' id='...'>
   >>> manager.mock_calls
   [call.MockClass1(),
   call.MockClass1().foo(),
   call.MockClass2(),
   call.MockClass2().bar()]

多くの呼び出しがあっても、そのうちの特定の一連の呼び出しだけを調べたい
場合は、"assert_has_calls()" メソッドも使えます。 このメソッドは、
"call" オブジェクトで作成した呼び出しのリストを受け取ります。 その一連
の呼び出しが "mock_calls" に含まれていれば、アサートは成功します。

>>> m = MagicMock()
>>> m().foo().bar().baz()
<MagicMock name='mock().foo().bar().baz()' id='...'>
>>> m.one().two().three()
<MagicMock name='mock.one().two().three()' id='...'>
>>> calls = call.one().two().three().call_list()
>>> m.assert_has_calls(calls)

モックに対する呼び出しが "m.one().two().three()" という連鎖した呼び出
しだけでなくても、アサートは成功します。

モックに複数回の呼び出しがあっても、その *一部* だけをアサートしたい場
合があります。 順序も問わない場合は、"assert_has_calls" に
"any_order=True" を渡せます。

>>> m = MagicMock()
>>> m(1), m.two(2, 3), m.seven(7), m.fifty('50')
(...)
>>> calls = [call.fifty('50'), call(1), call.seven(7)]
>>> m.assert_has_calls(calls, any_order=True)


より複雑な引数の照合
--------------------

"ANY" と同じ基本的な考え方でマッチャーを実装し、モックに引数として渡さ
れたオブジェクトに対して、より複雑なアサートを行えます。

オブジェクトの同一性に基づいて等価性を比較するオブジェクトが、モックに
渡されることを期待しているとします (Python のユーザー定義クラスのデフ
ォルトの比較方法です)。 "assert_called_with()" を使うには、まったく同
じオブジェクトを渡す必要があります。 そのオブジェクトの一部の属性だけ
を調べたい場合は、それらの属性を検査するマッチャーを作成できます。

この例では、"assert_called_with" の「通常の」呼び出しでは不十分である
ことがわかります。

>>> class Foo:
...     def __init__(self, a, b):
...         self.a, self.b = a, b
...
>>> mock = Mock(return_value=None)
>>> mock(Foo(1, 2))
>>> mock.assert_called_with(Foo(1, 2))
Traceback (most recent call last):
    ...
AssertionError: expected call not found.
Expected: mock(<__main__.Foo object at 0x...>)
Actual: mock(<__main__.Foo object at 0x...>)

"Foo" クラスの比較関数は、例えば次のようになります。

>>> def compare(self, other):
...     if not type(self) == type(other):
...         return False
...     if self.a != other.a:
...         return False
...     if self.b != other.b:
...         return False
...     return True
...

このような比較関数を等価性の判定に使うマッチャーオブジェクトは、例えば
次のようになります。

>>> class Matcher:
...     def __init__(self, compare, some_obj):
...         self.compare = compare
...         self.some_obj = some_obj
...     def __eq__(self, other):
...         return self.compare(self.some_obj, other)
...

全てをつなぎ合わせて:

>>> match_foo = Matcher(compare, Foo(1, 2))
>>> mock.assert_called_with(match_foo)

"Matcher" は、比較関数と、比較対象の "Foo" オブジェクトを渡してインス
タンス化します。 "assert_called_with" の中で "Matcher" の等価性比較メ
ソッドが呼ばれ、 モックに渡されたオブジェクトと、マッチャーの作成時に
指定したオブジェクトを比較します。 一致すれば "assert_called_with" は
成功し、一致しなければ "AssertionError" を送出します。

>>> match_wrong = Matcher(compare, Foo(3, 4))
>>> mock.assert_called_with(match_wrong)
Traceback (most recent call last):
    ...
AssertionError: Expected: ((<Matcher object at 0x...>,), {})
Called with: ((<Foo object at 0x...>,), {})

少し変更すれば、比較関数から直接 "AssertionError" を送出し、より役立つ
失敗メッセージを示すこともできます。

Python のテストライブラリ PyHamcrest は、バージョン 1.5 以降、 等価性
マッチャー (hamcrest.library.integration.match_equality) として同様の
機能を提供しており、ここで役立つかもしれません。
