web-dev-qa-db-ja.com

Pythonインポートされたモジュールから関数をモックする

インポートされたモジュールから関数を@patchする方法を理解したい。

これは私がこれまでのところです。

app/mocking.py:

from app.my_module import get_user_name

def test_method():
  return get_user_name()

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

app/my_module/__ init__.py:

def get_user_name():
  return "Unmocked User"

test/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 __== '__main__':
  unittest.main()

これはnot期待通りに動作します。 「パッチを適用した」モジュールは、単にget_user_nameのモックされていない値を返します。テスト中のネームスペースにインポートしている他のパッケージのメソッドをモックするにはどうすればよいですか?

82
nsfyn55

unittest.mockパッケージのpatchデコレーターを使用している場合、モジュールのインポート元のネームスペースにパッチを適用しているnotこの場合はapp.my_module.get_user_name)テスト対象の名前空間app.mocking.get_user_nameにパッチを適用しています。

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 が含まれています。

116
Matti John

Matti Johnの答えはあなたの問題を解決します(そして、私も助けてくれました、ありがとう!)、しかし、私は、元の 'get_user_name'関数の代わりをモックされた関数にローカライズすることをお勧めします。これにより、関数が置き換えられるときと置き換えられないときを制御できます。また、これにより、同じテストで複数の置換を行うことができます。そのためには、「with」文をかなり似た方法で使用します。

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')
7
Tgilgul