2013-04-21 13 views
46

インポートされたモジュールの関数@patchを理解したいと思います。Pythonインポートされたモジュールの関数を模倣する

これまでのところ、これがここにあります。

アプリ/ mocking.py:

from app.my_module import get_user_name 

def test_method(): 
    return get_user_name() 

if __name__ == "__main__": 
    print "Starting Program..." 
    test_method() 

アプリ/ my_module/__ init__.py:

def get_user_name(): 
    return "Unmocked User" 

テスト/ mock-test.py:

import unittest 
from app.mocking import test_method 

def mock_get_user(): 
    return "Mocked This Silly" 

@patch('app.my_module.get_user_name') 
class MockingTestTestCase(unittest.TestCase): 

    def test_mock_stubs(self, mock_method): 
    mock_method.return_value = 'Mocked This Silly') 
    ret = test_method() 
    self.assertEqual(ret, 'Mocked This Silly') 

if __name__ == '__main__': 
    unittest.main() 

これはではなく、の仕事を期待しています。 「patched」モジ​​ュールは、単に、ロックされていない値get_user_nameを返します。テスト中の名前空間にインポートする他のパッケージからメソッドをモックするにはどうすればよいですか?

+1

質問は「からかっベストプラクティス」についてまたはあなたがやっていることは理にかなっているかどうかではないでしょうか?最初は、Python3.3 +に含まれている['Mock'](http://www.voidspace.org.uk/python/mock/)のような模倣ライブラリを使用すると言っていましたが、[' unittest .mock'](http://docs.python.org/dev/library/unittest.mock)を参照してください。 – Bakuriu

+0

私はこの権利について行くかどうか尋ねています。私はモックを見ましたが、この特定の問題を解決する方法はありません。私がモックで行ったことを再現する方法はありますか? – nsfyn55

答えて

66

あなたはモジュールが(この場合はapp.my_module.get_user_nameに)あなたは、テストapp.mocking.get_user_name下の名前空間でそれをパッチを適用しているから輸入された名前空間をパッチないあるunittest.mockパッケージからpatchデコレータを使用しています。 Mockで上記の操作を行うに

は、以下のようなものを試してください:

from mock import patch 
from app.mocking import test_method 

class MockingTestTestCase(unittest.TestCase): 

    @patch('app.mocking.get_user_name') 
    def test_mock_stubs(self, test_patch): 
     test_patch.return_value = 'Mocked This Silly' 
     ret = test_method() 
     self.assertEqual(ret, 'Mocked This Silly') 

標準ライブラリのドキュメントがこれを記述した便利なsectionが含まれています。

+0

これは私の問題になります。 'get_user_name'は' test_method'とは別のモジュールにあります。 sub_moduleで何かを模擬する方法はありますか?私は下の醜い方法でそれを修正した。 – nsfyn55

+4

'get_user_name'は' test_method'とは別のモジュールに入っていても問題はありません。同じ名前空間にある 'app.mocking'に関数をインポートしているからです。 –

+0

が見つかりました。うん、うまくいくよ! – nsfyn55

5

Matti Johnの答えがあなたの問題を解決してくれました(そして私も助けてくれました)が、元の 'get_user_name'関数の置き換えを模擬したものにローカライズすることをお勧めします。これにより、機能がいつ置き換えられ、いつ機能しないかを制御することができます。また、同じテストでいくつかの置き換えを行うことができます。そうするためには、かなりsimillarようにしなステートメント「で」を使用:

from mock import patch 

class MockingTestTestCase(unittest.TestCase): 

    def test_mock_stubs(self): 
     with patch('app.mocking.get_user_name', return_value = 'Mocked This Silly'): 
      ret = test_method() 
      self.assertEqual(ret, 'Mocked This Silly') 
+0

これはポーズされた質問にとって重要ではないです。デコレータやコンテキストマネージャとして 'patch'を使うかどうかは、ユースケースに特有です。たとえば、 'patch'をデコレータとして使用して、' xunit'や 'pytest'クラスのすべてのテストの値をモックすることができます。他の場合は、コンテキストマネージャが細かい制御を行うのに便利です。 – nsfyn55

関連する問題