web-dev-qa-db-ja.com

pythonモックを使用したモック関数

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は、モックされた関数を指していないという点で、ここで非難されるかもしれません。

58
shreddd

回避策があると思いますが、一般的なケースを解決する方法はまだ明確ではありません

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を指します。

名前空間の問題が判明-コードを作成するときは、そのことを念頭に置いてください。

28
shreddd

使用されている関数にパッチを適用する必要があります。あなたの場合、それは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

23
Simon Luijk

モジュール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をインポートします)。

9
samplebias

一般的なケースは、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_contentmymoduleで使用しているため。

上記は、モックv2.0.0、nosetests v1.3.7およびpython v2.7.9。

9
KanAfghan

質問への直接的な回答を提供するものではありませんが、別の可能な選択肢は、@ staticmethodを使用して関数を静的メソッドに変換することです。

したがって、次のような方法でモジュールutilsをクラスに変換できます。

class util(object):
     @staticmethod
     def get_content():
         return "stuff"

次に、それを正しくモックします。

1
zom-pro