2014-11-05 3 views
1

값 비싼 __init__ 클래스가 있습니다. 나는이 함수가 테스트에서 호출되는 것을 원하지 않는다. 조롱 된 클래스의 __init__ 실행을 피하십시오

class ClassWithComplexInit(object): 

    def __init__(self): 
     raise Exception("COMPLEX!") 

    def get_value(self): 
     return 'My value' 

내가 ClassWithComplexInit의 인스턴스를 생성하고이 함수의 사용 번째 클래스가이 실시 예의 목적

, 난 __init__에 예외가 발생하는 클래스를 만들었다.

class SystemUnderTest(object): 

    def my_func(self): 
     foo = ClassWithComplexInit() 
     return foo.get_value() 

SystemUnderTest#my_func() 주위에 단위 테스트를 쓰려고합니다. 내가 겪고있는 문제는 아무리 시도해도 ClassWithComplexInit 일 때 __init__ 함수가 항상 실행되고 예외가 발생합니다.

class TestCaseWithoutSetUp(unittest.TestCase): 

    @mock.patch('mypackage.ClassWithComplexInit.get_value', return_value='test value') 
    def test_with_patched_function(self, mockFunction): 
     sut = SystemUnderTest() 
     result = sut.my_func() # fails, executes ClassWithComplexInit.__init__() 
     self.assertEqual('test value', result) 

    @mock.patch('mypackage.ClassWithComplexInit') 
    def test_with_patched_class(self, mockClass): 
     mockClass.get_value.return_value = 'test value' 
     sut = SystemUnderTest() 
     result = sut.my_func() # seems to not execute ClassWithComplexInit.__init__() 
     self.assertEqual('test value', result) # still fails 
     # AssertionError: 'test value' != <MagicMock name='ClassWithComplexInit().get_value()' id='4436402576'> 

위의 두 번째 방법은 this similar Q&A에서 가져온 것이지만 작동하지 않습니다. 그것은 함수를 실행하지 않으려면 같았지만 결과는 내 값에 반대 모의 인스턴스가 끝나기 때문에 내 주장은 실패합니다.

는 또한 the docs suggeststartstop 기능을 사용하여 setUp 기능에 patch 인스턴스를 구성했습니다.

class TestCaseWithSetUp(unittest.TestCase): 

    def setUp(self): 
     self.mockClass = mock.MagicMock() 
     self.mockClass.get_value.return_value = 'test value' 
     patcher = mock.patch('mypackage.ClassWithComplexInit', self.mockClass) 
     patcher.start() 
     self.addCleanup(patcher.stop) 

    def test_my_func(self): 
     sut = SystemUnderTest() 
     result = sut.my_func() # seems to not execute ClassWithComplexInit.__init__() 
     self.assertEqual('test value', result) # still fails 
     # AssertionError: 'test value' != <MagicMock name='mock().get_value()' id='4554658128'> 

이것은 또한 내 __init__ 기능을 피하기 위해 보이지만 내가 get_value.return_value 설정 값이 존중되지 않는 및 get_value() 여전히 MagicMock 인스턴스를 반환합니다.

테스트중인 코드에 의해 인스턴스화 된 __init__의 복잡한 클래스를 어떻게 조롱 할 수 있습니까? 이상적으로는 TestCase 클래스 내에서 많은 단위 테스트 (예 : patch 모든 테스트 필요 없음)에서 잘 작동하는 솔루션을 원합니다.

저는 파이썬 버전 2.7.6을 사용하고 있습니다.

+0

어떻게 테스트 스크립트에서'ClassWithComplexInit'을 사용할 수 있습니까? 'mypackage import ClassWithComplexInit' 또는 다른 것? – chepner

+0

@chepner 제 테스트 스크립트가'ClassWithComplexInit'을 가져 오지 않았습니다. 나는 실제 코드에서 많은 코드를 여기에 게시하여 패키지 참조를 엉망으로 만든다. 참조가 잘못되었다는 것을 알았다.당신은 당신의 대답에 이것을 설명합니다, 고마워요! –

답변

1

먼저, 당신은 당신이 올바른 모의 개체를 구성해야합니다, 즉, 당신이 foo를 만들 패치하는 동일한 이름을 사용하는

class SystemUnderTest(object): 

    def my_func(self): 
     foo = mypackage.ClassWithComplexInit() 
     return foo.get_value() 

둘째가 필요합니다. 언 바운드 방식 인 ClassWithComplexInit.get_value을 구성했지만 foo.get_value()으로 실제로 호출 될 Mock 개체 인 ClassWithComplexInit.return_value.get_value을 구성해야합니다.

@mock.patch('mypackage.ClassWithComplexInit') 
def test_with_patched_class(self, mockClass): 
    mockClass.return_value.get_value.return_value = 'test value' 
    sut = SystemUnderTest() 
    result = sut.my_func() # seems to not execute ClassWithComplexInit.__init__() 
    self.assertEqual('test value', result) # still fails 
+0

이것은 효과가 있습니다! 나는 또한이 접근 방식을 [연쇄 호출을 조롱하는 문서] (http://www.voidspace.org.uk/python/mock/examples.html#mocking-chained-calls)에서 보았습니다. 나는 해결책을 직접 게시하려했으나 당신은 나를 때렸다. –

+0

또한,'mockClass.return_value.get_value.return_value'라는 표현은'mockClass(). get_value.return_value'로 대체 될 수 있으며 여전히 작동합니다. –

+0

아, 맞아. mock은 클래스를 채우고 있는지 모르기 때문에'ClassWithComplexInit .__ new__'에 대한 모든 "호출"은 같은 객체를 반환 할 것이고 한 객체의'get_value()'메소드의 반환 값을 설정하면 그렇게 할 것입니다 그들 모두를 위해서. – chepner

-1

테스트 용으로 하위 클래스를 만들고 init을 덮어 쓰지 않는 이유는 무엇입니까? 'My value' 대신 예외를 발생시키는의 지금

class testClassWithComplexInit(ClassWithComplexInit): 
    def __init__(self): 
     pass 

ClassWithComplexInit = testClassWithComplexInit 

, ClassWithComplexInit().get_value() 돌아갑니다.

+0

'__init__' 함수는 모의하려고하는 유일한 함수는 아니지만 모의 객체를 사용하고자하는 다른 복잡한 함수가 있습니다. 클래스의 인스턴스가 실제로 사용되기를 원하지 않습니다. 하위 클래스조차도 사용하지 않으려합니다. 왜냐하면 모든 클래스가 '통과'함수를 사용하지 않아야하기 때문입니다. –

+0

또한이 클래스 인스턴스는 전달되지 않고'SystemUnderTest'에서 인스턴스화됩니다. 클래스의'testClassWithComplexInit' 버전을 어떻게 사용하게할까요? –

관련 문제