モックvs MagicMock


138

私の理解では、MagicMockは自動的に「マジックメソッド」を実行するMockのスーパーセットであり、リスト、反復などのサポートをシームレスに提供します...では、プレーンMockが存在する理由は何ですか?それは、MagicMockの一部を取り除いたバージョンであり、実際には無視できますか?DOES モッククラスがで使用できないすべてのトリックを知ってMagicMockを

回答:


99

プレーンモックが存在する理由は何ですか?

Mockの作者であるMichael Foordは、Pycon 2011(31:00)で非常によく似た質問に答えました

Q:なぜMagicMockは、デフォルトのモックオブジェクトに機能を折り畳むだけでなく、別の物を作ったのですか?

A: 1つの合理的な答えは、MagicMockが機能する方法は、新しいモックを作成して設定することにより、これらすべてのプロトコルメソッドを事前構成することです。そのため、すべての新しいモックが新しいモックの束を作成し、それらをプロトコルメソッドとして設定してから、それらすべてのプロトコルを設定します。メソッドはより多くのモックを作成し、それらをプロトコルメソッドに設定すると、無限の再帰が得られます...

コンテナーオブジェクトとしてモックにアクセスしてエラーを発生させたい場合はどうすればよいですか?すべてのモックが自動的にすべてのプロトコルメソッドを取得している場合、それを行うのははるかに困難になります。また、MagicMockはこの事前構成の一部を行い、適切でない可能性がある戻り値を設定するので、すべてが事前構成されて利用できる便利なものを用意する方が良いと思いましたが、通常のモックを使用することもできますオブジェクトを作成し、存在させたい魔法のメソッドを設定するだけです...

簡単な答えは、MagicMockを使用したい場合はどこでも使用することです。


12
より良い答えは次のとおりだと思います。自分が何をしているかわかっている場合はMagicMockを使用し、そうでない場合はMockを使用してください。
laike9m 2017年

56

Mockを使用すると、マジックメソッドモックできますが、それらを定義する必要があります。MagicMockには「ほとんどの魔法のメソッドのデフォルト実装」があります。

マジックメソッドをテストする必要がない場合は、Mockで十分であり、無関係なことをテストに取り入れることはありません。多くのマジックメソッドをテストする必要がある場合、MagicMockは時間を節約します。


案の定、私はすでにドキュメントを読みました。それでも私の質問には答えません。MagicMockがまったく同じことをしているのに、どうしてプレーンモックに悩まされるのでしょうか。テストでは無関係なことは何も表示されません。別の名前を使用するだけです。では、どこに漁獲物があるのでしょうか?
ウラジミールイグナトフ2013年

39
テストは最小限であり、モックオブジェクトは最小限の機能である必要があります。これにより、テスト対象を正確に把握できます。「MagicMock」を使用する理由は、それがより多くのことを行うが、「すべて」を明示的にテストしていない場合、デフォルトのMagicMockの動作が原因でテストが失敗するリスクがあるためです。この失敗は、MagicMockのデフォルトについて、それが模倣するはずのものよりも何かを反映している可能性があります。さらに悪いことに、失敗したはずのテストが成功するリスクがあります。リスクは小さいですが、これが発生すると、多くの時間を浪費します。
Sean Redmond 2013年

1
プレーンなJSとJqueryを使用するようなものだと思います。もちろん、Jqueryを使用してすべてのJSを実行できますが、場合によっては、ジョブを完了するために必要な最小限のツールを使用したいだけです。私はそれらのケースが通常非常に単純であるか、非常に複雑であることに気づきます。
2015年

49

まずMagicMock、はのサブクラスですMock

class MagicMock(MagicMixin, Mock)

その結果、MagicMockはMockが提供するものすべてを提供します。MockをMagicMockのストリップバージョンと考えるのではなく、MagicMockをMockの拡張バージョンと考えてください。これは、Mockが存在する理由と、MockがMagicMockに何を提供するかについての質問に対処する必要があります。

第二に、MagicMockは多くの/ほとんどのマジックメソッドのデフォルト実装を提供しますが、Mockは提供しません。提供されているマジックメソッドの詳細については、ここを参照してください。

提供されているマジックメソッドの例:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

そして、これらは直感的ではないかもしれません(少なくとも私には直感的ではありません):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

これらのメソッドが初めて呼び出されるときに、MagicMockに追加されたメソッドを「見る」ことができます。

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

それでは、MagicMockを常に使用しないのはなぜですか?

あなたへの質問は次のとおりです。デフォルトのマジックメソッドの実装で大丈夫ですか?たとえば、mocked_object[1]エラーを出さなくても大丈夫ですか?マジックメソッドの実装がすでに存在しているため、意図しない結果が発生しても大丈夫ですか?

これらの質問に対する答えが「はい」の場合は、先に進んでMagicMockを使用してください。それ以外の場合は、モックに固執します。


12

これはpythonの公式ドキュメントが 言うことです:

これらの例のほとんどで、MockクラスとMagicMockクラスは交換可能です。MagicMockはより有能なクラスであるため、デフォルトで使用するのが賢明です。


3

simpleの Mock方が便利場合がある別の特定のケースを見つけましたMagicMock

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

比較すると、ANYいくつかの値が偽を使用して計算される2つの辞書の間のほぼすべてのキーを比較し、例えば、有用であり得ます。

これは、以下を使用している場合に有効ですMock


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

AssertionErrorあなたが使用した場合、それは発生しますがMagicMock

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.