2015-02-03 4 views
42

다른 함수 (bar)를 호출하는 함수 (foo)가 있습니다. bar()을 호출하면 HttpError이 발생합니다. 상태 코드가 404이면 특별히 처리하고 싶습니다. 그렇지 않으면 다시 올립니다.예외 블록을 테스트하기 위해 예외를 발생시키는 함수 모의

bar()으로 전화를 조롱하면서이 foo 함수와 관련된 단위 테스트를 작성하려고합니다. 죄송 합니다만, bar()으로 조롱 한 전화를 받아서 except 블록에 걸려있는 예외를 발생시킬 수 없습니다.

import unittest 
import mock 
from apiclient.errors import HttpError 


class FooTests(unittest.TestCase): 
    @mock.patch('my_tests.bar') 
    def test_foo_shouldReturnResultOfBar_whenBarSucceeds(self, barMock): 
     barMock.return_value = True 
     result = foo() 
     self.assertTrue(result) # passes 

    @mock.patch('my_tests.bar') 
    def test_foo_shouldReturnNone_whenBarRaiseHttpError404(self, barMock): 
     barMock.side_effect = HttpError(mock.Mock(return_value={'status': 404}), 'not found') 
     result = foo() 
     self.assertIsNone(result) # fails, test raises HttpError 

    @mock.patch('my_tests.bar') 
    def test_foo_shouldRaiseHttpError_whenBarRaiseHttpErrorNot404(self, barMock): 
     barMock.side_effect = HttpError(mock.Mock(return_value={'status': 500}), 'error') 
     with self.assertRaises(HttpError): # passes 
      foo() 

def foo(): 
    try: 
     result = bar() 
     return result 
    except HttpError as error: 
     if error.resp.status == 404: 
      print '404 - %s' % error.message 
      return None 
     raise 

def bar(): 
    raise NotImplementedError() 

나는 당신이 조롱 기능은 오류가 발생해야하는 Exception 클래스에 Mock 인스턴스의 side_effect을 설정해야한다고 말하는 Mock docs 다음 :

다음은 내 문제를 보여 내 코드입니다.

나는 또한 다른 관련 StackOverflow Q &을 보았다. 그리고 나는 그들이하고있는 것과 똑같은 일을하고있는 것처럼 보이고, 그들의 모의에 의해 제기 된 Exception을 보였다.

Exception을 예상하는 것은 제기하는 원인이되지 side_effect barMock의 설정입니다

? 이상한 일을하고 있다면, 내 except 블록에서 로직 테스트를 어떻게해야합니까?

+0

나는 당신의 예외 *가 제기되고 있음을 확신하지만 거기에서'resp.status' 코드를 어떻게 설정하고 있는지 모르겠습니다. 'HTTPError'는 어디에서 왔습니까? –

+0

@MartijnPieters'HttpError'는 GAE에서 사용하는 [Google의'apiclient' lib] (https://developers.google.com/api-client-library/python/)에 정의 된 클래스입니다. '__init__'는 매개 변수'(resp, content)'로 정의되었으므로 응답을위한 mock 인스턴스를 생성하려고 시도했습니다. 적절한 상태 코드가 지정되었습니다. –

+0

맞아요, [this class] (https://github.com/google/google-api-python-client/blob/master/googleapiclient/errors.py#L35-L63); 하지만 사용자는'return_value'를 할 필요가 없습니다; 'resp'는 * 호출되지 않습니다 *. –

답변

54

모의 예외가 발생하지만 error.resp.status 값이 누락되었습니다. Mock()

barMock.side_effect = HttpError(mock.Mock(status=404), 'not found') 

추가 키워드 인수는 결과 객체에 속성으로 설정됩니다 status가 속성 인 것을 오히려 사용 return_value보다, 단지 Mock을 말한다.

는 I는 my_tests 모듈에 foobar 정의를 넣어 그래서 너무 사용할 수있는 HttpError class에 추가하고, 테스트 후 성공을 실행 할 수 있습니다

>>> from my_tests import foo, HttpError 
>>> import mock 
>>> with mock.patch('my_tests.bar') as barMock: 
...  barMock.side_effect = HttpError(mock.Mock(status=404), 'not found') 
...  result = my_test.foo() 
... 
404 - 
>>> result is None 
True 

당신은 심지어 print '404 - %s' % error.message를 볼 수 있습니다 줄을 실행하지만, 대신 error.content을 사용하고 싶다고 생각합니다. 어쨌든 두 번째 인수에서 설정 한 HttpError() 속성입니다.

+0

이것은 트릭을 했어, 고마워! –