unittest setUp으로 mock을 사용하는 방법
TDD를 배우려는 시도에서 단위 테스트를 배우고로 mock을 사용합니다. 천천히 확실하게 알고 있는지 확인합니다. 미리 경고 : 공급 업체 API가 미리 준비된 2.4 pyc 파일로 제공되기 때문에 python 2.4를 사용하고 있습니다. 그래서 mock 0.8.0 및 unittest (unittest2가 아님)를 사용하고 있습니다.
이 예제 코드는 'mymodule.py'에 있습니다.
import ldap
class MyCustomException(Exception):
pass
class MyClass:
def __init__(self, server, user, passwd):
self.ldap = ldap.initialize(server)
self.user = user
self.passwd = passwd
def connect(self):
try:
self.ldap.simple_bind_s(self.user, self.passwd)
except ldap.INVALID_CREDENTIALS:
# do some stuff
raise MyCustomException
이제 테스트 케이스 파일 'test_myclass.py'에서 ldap를 모의 처리하고 싶습니다. ldap.initialize는 ldap.ldapobject.SimpleLDAPObject를 반환하여 모의 처리해야 할 방법이라고 생각했습니다.
import unittest
from ldap import INVALID_CREDENTIALS
from mock import patch, MagicMock
from mymodule import MyClass
class LDAPConnTests(unittest.TestCase):
@patch('ldap.initialize')
def setUp(self, mock_obj):
self.ldapserver = MyClass('myserver','myuser','mypass')
self.mocked_inst = mock_obj.return_value
def testRaisesMyCustomException(self):
self.mocked_inst.simple_bind_s = MagicMock()
# set our side effect to the ldap exception to raise
self.mocked_inst.simple_bind_s.side_effect = INVALID_CREDENTIALS
self.assertRaises(mymodule.MyCustomException, self.ldapserver.connect)
def testMyNextTestCase(self):
# blah blah
몇 가지 질문으로 연결됩니다.
- 그게 맞나요? :)
- 내가 테스트하는 클래스 내에서 인스턴스화되는 클래스를 시도하고 조롱하는 적절한 방법입니까?
- setUp에서 @patch 데코레이터를 호출해도 괜찮습니까? 아니면 이상한 부작용이 발생 했습니까?
- 어떤 경우에도 내 테스트 케이스 파일로 예외를 필요없이 ldap.INVALID_CREDENTIALS 예외를 발생시키기 위해 모의 사용할 수 있습니까?
- 대신 patch.object ()를 사용하며 어떻게해야합니까?
감사합니다.
patch()
함수 데코레이터 프리미엄 클래스 데코레이터로 사용할 수 있습니다 . 그런 다음 이전과 같이 mocked 함수를 사용할 수 있습니다.
@patch('mymodule.SomeClass')
class MyTest(TestCase):
def test_one(self, MockSomeClass):
self.assertIs(mymodule.SomeClass, MockSomeClass)
참조 : 26.5.3.4. 모든 테스트 방법에 동일한 패치 적용 (대안 사항도 모든 테스트 )
모든 테스트 방법은 패치를 수행하는 방식으로 패치 프로그램을 설정하는 것이 더 합리적입니다.
나는 당신의 질문에 답하여 다음 나는 방법에 대한 자세한 예를주지 patch()
와 setUp()
상호 작용합니다.
- 옳지 않다고 생각합니다. 자세한 내용은이 목록의 질문 # 3에 대한 제 답변을 참조하십시오.
- 예, 패치에 대한 실제 호출은 원하는 개체를 모의 해야하는 것처럼 보입니다.
- 아니요,
@patch()
데코레이터 를 사용하고 싶지 않습니다setUp()
. 개체가 생성되지setUp()
않기 때문에 테스트 방법 이 생성되지 않습니다 . - 모의 발생가 예외를 테스트 케이스 파일로 가져 오는 오지 예외를 발생시키는 방법을 모르겠습니다.
- 나는
patch.object()
여기에 대한 어떤 필요도 보지 않는다 . 대상을 패키지로 지정하는 대신 객체의 속성을 패치 할 수 있습니다.
질문 # 3에 대한 답을 확장하기 위해 문제는 patch()
데코레이터가 데코 레이팅 된 함수가 실행되는 동안에 만 응용 프로그램입니다. setUp()
반환되는 즉시 패치가 제거됩니다. 당신의 경우에는 작동하지만이 테스트를 보는 사람을 혼란스럽게 할 것입니다. 밤 패치가에서 발생 하기를, 패치가 제거 될 것임을 분명히하기 위해 문장을 setUp()
사용하는 것이 with
좋습니다.
다음 예제에는 두 개의 테스트 케이스가 있습니다. TestPatchAsDecorator
클래스를 꾸미면 테스트 방법 패치가 적용됩니다 setUp()
. TestPatchInSetUp
패치를 적용하는 setUp()
방법과 테스트 방법 모두에서 제자리에 있는지 보여줍니다 . 호출 self.addCleanUp()
하면 패치가 tearDown()
.
import unittest
from mock import patch
@patch('__builtin__.sum', return_value=99)
class TestPatchAsDecorator(unittest.TestCase):
def setUp(self):
s = sum([1, 2, 3])
self.assertEqual(6, s)
def test_sum(self, mock_sum):
s1 = sum([1, 2, 3])
mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)
class TestPatchInSetUp(unittest.TestCase):
def setUp(self):
patcher = patch('__builtin__.sum', return_value=99)
self.mock_sum = patcher.start()
self.addCleanup(patcher.stop)
s = sum([1, 2, 3])
self.assertEqual(99, s)
def test_sum(self):
s1 = sum([1, 2, 3])
self.mock_sum.return_value = 42
s2 = sum([1, 2, 3])
self.assertEqual(99, s1)
self.assertEqual(42, s2)
적용 할 패치가 많고 setUp 메서드에서 초기화 된 항목에도 적용하려면 다음을 시도하십시오.
def setUp(self):
self.patches = {
"sut.BaseTestRunner._acquire_slot": mock.Mock(),
"sut.GetResource": mock.Mock(spec=GetResource),
"sut.models": mock.Mock(spec=models),
"sut.DbApi": make_db_api_mock()
}
self.applied_patches = [mock.patch(patch, data) for patch, data in self.patches.items()]
[patch.apply for patch in self.applied_patches]
.
. rest of setup
.
def tearDown(self):
patch.stopall()
new
인수가 patch()
데코레이터 에게 전달 되는 허용되는 답변의 변형을 지적하고 싶습니다 .
from unittest.mock import patch, Mock
MockSomeClass = Mock()
@patch('mymodule.SomeClass', new=MockSomeClass)
class MyTest(TestCase):
def test_one(self):
# Do your test here
이 경우 더 이상 MockSomeClass
모든 테스트 메서드에 두 번째 인수를 추가 할 필요가 없으므로 많은 코드 반복을 줄일 수 있습니다.
이에 대한 설명은 https://docs.python.org/3/library/unittest.mock.html#patch 에서 찾을 수 있습니다 .
경우
patch()
데코레이터로 사용되는 새로운 생략, 생성 된 모의은 장식 기능을 추가 인수로 전달됩니다.
무엇보다도 new를 생략 했지만 포함하는 것이 편리 할 수 있습니다.
패치 된 내부 함수를 만들고에서 호출 할 수 있습니다 setUp
.
원래 setUp
기능이 다음과 같은 경우 :
def setUp(self):
some_work()
그런 다음 다음으로 변경하여 패치 할 수 있습니다.
def setUp(self):
@patch(...)
def mocked_func():
some_work()
mocked_func()
참조 URL : https://stackoverflow.com/questions/15821465/how-to-properly-use-mock-in-python-with-unittest-setup
'ProgramingTip' 카테고리의 다른 글
ActionBar의 아이콘을 동적으로 변경 (0) | 2021.01.07 |
---|---|
내부 .NET Framework 데이터 공급자 오류 1025 (0) | 2021.01.07 |
다른 지점에서 tree-ish를`git log`하는 방법은 무엇입니까? (0) | 2021.01.07 |
Git 경고 : push.default가 설정되지 않았습니다. (0) | 2021.01.07 |
부모 RecyclerView 안에있는 방법은 무엇입니까? (0) | 2021.01.07 |