pythonモックモジュール(http://www.voidspace.org.uk/python/mock/index.html)を使用して、関数(一部の外部コンテンツを返す)をモックしようとしています。
モジュールにインポートされた関数のモック作成に問題があります。
たとえば、util.pyには
def get_content():
return "stuff"
Util.get_contentをモックして、他の何かを返すようにします。
私はこれを試しています:
util.get_content=Mock(return_value="mocked stuff")
get_content
は別のモジュール内で呼び出され、実際にはモックされたオブジェクトを返すことはありません。 Mockの使用方法に関して何か不足していますか?
以下を呼び出すと、物事が正しく機能することに注意してください。
>>> util.get_content=Mock(return_value="mocked stuff")
>>> util.get_content()
"mocked stuff"
ただし、get_contentが別のモジュール内から呼び出された場合、モックバージョンではなく元の関数を呼び出します。
>>> from mymodule import MyObj
>>> util.get_content=Mock(return_value="mocked stuff")
>>> m=MyObj()
>>> m.func()
"stuff"
Mymodule.pyの内容
from util import get_content
class MyObj:
def func():
get_content()
だから私は私の質問だと思います-私が呼び出すモジュール内から関数のモックバージョンを呼び出すにはどうすればよいですか?
from module import function
は、モックされた関数を指していないという点で、ここで非難されるかもしれません。
回避策があると思いますが、一般的なケースを解決する方法はまだ明確ではありません
Mymoduleで、交換する場合
from util import get_content
class MyObj:
def func():
get_content()
と
import util
class MyObj:
def func():
util.get_content()
モックが呼び出されるようです。名前空間が一致する必要があるように見えます(これは理にかなっています)。しかし、奇妙なことは私が期待することです
import mymodule
mymodule.get_content = mock.Mock(return_value="mocked stuff")
from/import構文(get_contentをmymoduleに取り込む)を使用している元のケースでトリックを実行します。ただし、これはまだモックされていないget_contentを指します。
名前空間の問題が判明-コードを作成するときは、そのことを念頭に置いてください。
使用されている関数にパッチを適用する必要があります。あなたの場合、それはmymoduleモジュールにあります。
import mymodule
>>> mymodule.get_content = Mock(return_value="mocked stuff")
>>> m = mymodule.MyObj()
>>> m.func()
"mocked stuff"
こちらのドキュメントにリファレンスがあります: http://docs.python.org/dev/library/unittest.mock.html#where-to-patch
モジュールfoobar
内にモックを作成すると仮定します。
_import util, mock
util.get_content = mock.Mock(return_value="mocked stuff")
_
mymodule
をインポートし、最初にfoobar
をインポートせずに_util.get_content
_を呼び出すと、モックはインストールされません。
_import util
def func()
print util.get_content()
func()
"stuff"
_
代わりに:
_import util
import foobar # substitutes the mock
def func():
print util.get_content()
func()
"mocked stuff"
_
_util.get_content
_が呼び出される前にfoobar
が評価される限り、foobar
はどこからでもインポートできます(モジュールAはfoobarをインポートするBをインポートします)。
一般的なケースは、patch
からmock
を使用することです。以下を考慮してください。
tils.py
def get_content():
return 'stuff'
mymodule.py
from util import get_content
class MyClass(object):
def func(self):
return get_content()
test.py
import unittest
from mock import patch
from mymodule import MyClass
class Test(unittest.TestCase):
@patch('mymodule.get_content')
def test_func(self, get_content_mock):
get_content_mock.return_value = 'mocked stuff'
my_class = MyClass()
self.assertEqual(my_class.func(), 'mocked stuff')
self.assertEqual(get_content_mock.call_count, 1)
get_content_mock.assert_called_once()
get_content
はm笑されているが、util.get_content
、むしろmymodule.get_content
mymodule
で使用しているため。
上記は、モックv2.0.0、nosetests v1.3.7およびpython v2.7.9。
質問への直接的な回答を提供するものではありませんが、別の可能な選択肢は、@ staticmethodを使用して関数を静的メソッドに変換することです。
したがって、次のような方法でモジュールutilsをクラスに変換できます。
class util(object):
@staticmethod
def get_content():
return "stuff"
次に、それを正しくモックします。