가져온 모듈에서 함수를 조롱하는 파이썬


125

@patch가져온 모듈에서 함수를 사용하는 방법을 이해하고 싶습니다 .

이것은 내가 지금까지있는 곳이다.

app / 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()

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

예상대로 작동 하지 않습니다 . "패치 된"모듈은 단순히의 모방되지 않은 값을 반환합니다 get_user_name. 테스트중인 네임 스페이스로 가져 오는 다른 패키지의 메서드를 어떻게 모의합니까?


1
질문은 "모의 모범 사례"에 관한 것입니까, 아니면 당신이하는 일이 타당한가? 첫 번째에 관해서는 Mockpython3.3 +에 unittest.mock.
Bakuriu

나는 내가이 권리에 대해 갈 것인지 묻고있다. Mock을 보았지만이 특정 문제를 해결할 방법을 찾지 못했습니다. Mock에서 위에서했던 작업을 재현 할 수있는 방법이 있습니까?
nsfyn55 2013

답변:


167

패키지 에서 patch데코레이터를 사용하는 경우 모듈을 가져온 네임 스페이스를 패치 하지 않습니다 (이 경우 ) . 테스트중인 네임 스페이스에서 패치를 적용합니다 .unittest.mockapp.my_module.get_user_nameapp.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')

표준 라이브러리 문서에는 이를 설명 하는 유용한 섹션 이 포함되어 있습니다.


이것은 내 문제에 도달합니다. get_user_name과 다른 모듈에 test_method있습니다. sub_module에서 무언가를 조롱하는 방법이 있습니까? 아래에서 추악한 방식으로 수정했습니다.
nsfyn55

6
동일한 네임 스페이스에있는 함수로 가져 오기 때문에 get_user_name다른 모듈에있는 것은 중요하지 않습니다 . test_methodapp.mocking
Matti John

2
test_patch는 어디에서 왔으며 정확히 무엇입니까?
마이크 G

2
test_patch는 패치 데코레이터에 의해 전달되며 모의 get_user_name 객체 (즉, MagicMock 클래스의 인스턴스)입니다. 이름이와 같은 경우 더 명확 할 수 있습니다 get_user_name_patch.
Matti John

test_method를 어떻게 참조하고 있습니까? 오류가 발생합니다. NameError : 전역 이름 'test_method'가 정의되지 않았습니다
Aditya

12

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

6
이것은 제기 된 질문에 대해 다소 중요하지 않습니다. patch데코레이터로 사용하는지 컨텍스트 관리자로 사용하는지 여부 는 사용 사례에 따라 다릅니다. 예를 들어 patch데코레이터로 사용 하여 xunit또는 pytest클래스의 모든 테스트에 대한 값을 모의 할 수 있지만 다른 경우에는 컨텍스트 관리자가 제공하는 세밀한 제어를 갖는 것이 유용합니다.
nsfyn55
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.