2013-04-04 1 views
38

TDD를 배우려고 시도하면서 단위 테스트를 배우고 모의 파이썬을 사용하려고했습니다. 천천히 그것의 걸림 새를 얻는, 그러나 나가 이것을 정확하게하고있는 경우에 불확실한. 미리 경고 : 저는 파이썬 2.4를 사용하고 있습니다. 왜냐하면 벤더 API가 미리 컴파일 된 2.4 파이크 파일이기 때문에 mock 0.8.0과 unittest (unittest2가 아닌)를 사용하고 있습니다.unittest setup으로 파이썬에서 mock을 올바르게 사용하는 방법

'mymodule.py '

이제 내 테스트 케이스 파일'test_myclass.py '에서 ldap 개체를 조롱하고 싶습니다. ldap.initialize는 ldap.ldapobject.SimpleLDAPObject를 반환하므로, 내가 조롱해야 할 방법이라고 생각했습니다.

  1. 합니까 제대로 보이지 :
    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 
    

    몇 가지 질문에 날 리드? :)
  2. 테스트하는 클래스 내에서 인스턴스화 된 객체를 모의 해보기위한 적절한 방법입니까?
  3. setUp에서 @patch 데코레이터를 호출하는 것이 좋습니까? 아니면 이상한 부작용을 유발할 수 있습니까?
  4. 예외를 내 테스트 케이스 파일로 가져 오지 않고도 ldap.INVALID_CREDENTIALS 예외를 발생시키는 모의 사례가 있습니까?
  5. 대신 patch.object()를 사용해야하며, 그렇다면 어떻게해야합니까?

감사합니다.

+1

1-3) 나에게 좋은 것 같은데 ... 4)'수입 ldap' 대신과'side_effect = ldap.INVALID_CREDENTIALS'을 설정? – Chris

+0

당신은 언제나 똑같은 테스트를 할 수 있지만, 더 간단한 오브젝트를 직접 만들 수 있습니다 ... – shackra

답변

36

참조 : 그것은 당신이 패치는 모든 시험 방법에 대해 수행되도록하려면 패쳐를 설정에이 방법을 설정하는 것이 더 의미가 26.5.3.4. Applying the same patch to every test method

.

+2

pre-Python3 Mock (http://www.voidspace.org.uk/python/mock/에서 호스팅)과 동일한 내용은 [모든 테스트 방법에 동일한 패치 적용] (http://www.voidspace.org.uk/python/mock/examples.html#applying-the-same-patch-to-every-test-method). – musiphil

+2

방금 ​​TestCase 클래스에서 클래스 수준의 모의가있는 곳에 문제가 발생하여'setUp()'메소드에서 호출 할 때 이미 그 위치에 있다고 가정했습니다. 그렇지 않다; 클래스 레벨 모의는'setUp()'에서 사용하기 위해 제 시간에 적용되지 않습니다. 대신 모든 테스트에서 사용하는 도우미 메서드를 만드는 방법으로이 문제를 해결했습니다. 이 방법이 최선의 방법인지는 모르지만 작동합니다. – berto

+0

@berto Answer에서 의견을 확장하면 도움이 될 것 같습니다. 여기에있는 다른 것보다 훨씬 쉽고 쉬운 솔루션입니다. – KobeJohn

4

당신은 적용 할 많은 패치가있는 경우 당신은 이것을 시도 너무 설치 방법에 초기화 것들에 적용을 원하는 :

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.stop_all() 
+3

'tearDown()'에서'patch.stop_all()'을 사용하는 것을 고려하십시오. –

+0

나는 이것을 시도했다. - applied_patches도 시작할 필요가있는 것 같다. 다음과 같은 줄을 고려해보십시오 :'for self.applied_patches : patch.start()' – F1Rumors

3

나는 당신의 질문에 답하여 시작합니다 다음 내가주지 patch()setUp()이 어떻게 상호 작용하는지에 대한 자세한 예입니다.

  1. 내가보기에 좋지 않을 것이라고 생각합니다. 자세한 내용은 answer # 3을 참조하십시오.
  2. 예, 패치를 실제로 호출하면 원하는 개체를 조롱해야합니다.
  3. 아니요, setUp()@patch() 데코레이터를 사용하고 싶지는 않을 것입니다. 행운의 이유는 객체가 setUp()에 만들어 졌기 때문에 테스트 메소드에서 결코 생성되지 않기 때문입니다.
  4. 모의 객체를 만들 때 테스트 케이스 파일에 예외를 가져 오지 않고 예외를 발생시키는 방법을 모르겠습니다.
  5. 여기에 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) 
관련 문제