次のサンプルコードでmock.patchを機能させようとしています:
from mock import patch
from collections import defaultdict
with patch('collections.defaultdict'):
d = defaultdict()
print 'd:', d
これは以下を出力します:
d: defaultdict(None, {})
つまり、defaultdictにはパッチが適用されていません。
From/importステートメントをストレートインポートステートメントに置き換えると、機能します。
from mock import patch
import collections
with patch('collections.defaultdict'):
d = collections.defaultdict()
print 'd:', d
出力は次のとおりです。
d: <MagicMock name='defaultdict()' id='139953944084176'>
From/importを使用して呼び出しにパッチを適用する方法はありますか?
ありがとうございました
同じモジュール内の何かにパッチを適用する場合は、__main__
を使用できます。
from mock import patch
from collections import defaultdict
with patch('__main__.defaultdict'):
d = defaultdict()
print 'd:', d
ただし、インポートしたモジュールのモックを作成している場合は、そのモジュールの名前を使用して、正しい参照(または名前)にパッチを適用する必要があります。
# foo.py
from collections import defaultdict
def bar():
return defaultdict()
# foo_test.py
from mock import patch
from foo import bar
with patch('foo.defaultdict'):
print bar()
ここでのポイントは、patchがパッチを適用する対象へのフルパスを必要としているということです。現在のモジュールで何かにパッチを当てるとき、これは少し奇妙に見えるだけです。なぜなら、人々は__main__
を頻繁に使用しないためです(または、現在のモジュールを参照する必要があるためです)。
patch
は、namesにパッチを適用することで機能します。オブジェクトにアクセスするためにdefaultdict
(ローカル名前空間内)の名前を使用している場合、名前collections.defaultdict
にパッチを適用しても何もできません。 http://www.voidspace.org.uk/python/mock/patch.html#id1 にあるドキュメントを参照してください。
この場合、名前は非常に混乱する可能性があります。私たちは常に名前空間のクラス定義をモックしたいと思っています。名前空間は、インポートが行われるモジュールです。クラス定義は、その名前空間で使用される名前です。
具体的な例を見てみましょう:
from myproj.utilities import Actor
としてインポートしますclass Actor:
def __init__(name):
self.name = name
from myproj.utilities import Actor
class App:
def __init__(name):
self.actor = Actor(name)
from mock import patch
from myproj.application import App
test:
# format: patch('<namespace>.<Class>')
# the namespace in which we with to mock
# the class definition we wish to mock
with patch('myproj.application.Actor'):
app = App('Someone')
print( type(app.actor) ) # expect a MagicMock
私は他のいくつかのアプローチを試しましたが、これは私にとってうまくいきます。上記のコードはテストしていませんが、自分の特定のケースから一般化しています。したがって、少しずれている可能性があります。