클래스 조롱 : Mock () 또는 patch ()?


116

나는 파이썬과 함께 mock 을 사용 하고 있으며 그 두 가지 접근법 중 어느 것이 더 나은지 궁금합니다 (읽기 : 더 파이썬).

방법 1 : 모의 객체를 만들고 사용하십시오. 코드는 다음과 같습니다.

def test_one (self):
    mock = Mock()
    mock.method.return_value = True 
    self.sut.something(mock) # This should called mock.method and checks the result. 
    self.assertTrue(mock.method.called)

방법 2 : 패치를 사용하여 모의를 만듭니다. 코드는 다음과 같습니다.

@patch("MyClass")
def test_two (self, mock):
    instance = mock.return_value
    instance.method.return_value = True
    self.sut.something(instance) # This should called mock.method and checks the result. 
    self.assertTrue(instance.method.called)

두 방법 모두 동일한 작업을 수행합니다. 차이점이 확실하지 않습니다.

누구든지 나를 깨달을 수 있습니까?


10
Mock ()이나 패치를 한 번도 해본 적이없는 사람으로서 실제 차이를 이해하지 못하더라도 첫 번째 버전이 더 명확하고하고 싶은 일을 보여줍니다. 이것이 도움이되는지 아닌지는 모르겠지만 초보 프로그래머가 느낄 수있는 것을 전달하는 것이 유용 할 것이라고 생각했습니다.
Michael Brennan 2011

2
@MichaelBrennan : 귀하의 의견에 감사드립니다. 참으로 유용합니다.
Sardathrion-SE 남용에 대하여

답변:


151

mock.patch와는 매우 다른 동물 mock.Mock입니다. 클래스를 모의 객체로 patch 대체 하고 모의 인스턴스로 작업 할 수 있습니다. 이 스 니펫을 살펴보십시오.

>>> class MyClass(object):
...   def __init__(self):
...     print 'Created MyClass@{0}'.format(id(self))
... 
>>> def create_instance():
...   return MyClass()
... 
>>> x = create_instance()
Created MyClass@4299548304
>>> 
>>> @mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
...   MyClass.return_value = 'foo'
...   return create_instance()
... 
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
...   print MyClass
...   return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass@4300234128
<__main__.MyClass object at 0x100505d90>

patchMyClass호출하는 함수에서 클래스 사용을 제어 할 수있는 방식으로 대체 됩니다. 클래스를 패치하면 클래스에 대한 참조가 모의 인스턴스로 완전히 대체됩니다.

mock.patch일반적으로 테스트 내부에 클래스의 새 인스턴스를 만드는 무언가를 테스트 할 때 사용됩니다. mock.Mock인스턴스가 더 명확하고 선호됩니다. self.sut.something메서드가 인스턴스를 MyClass매개 변수로받는 대신 인스턴스를 만든 경우 mock.patch여기에 적합합니다.


2
@ D.Shawley는 테스트 중이어야하는 다른 클래스 내부에서 인스턴스화 된 클래스에 어떻게 패치합니까?
ravi404 2013

4
@ravz- "패치 할 위치" 를 읽어보십시오. 이것은 제대로 작동하기 위해 더 어려운 일 중 하나입니다.
D.Shawley

내 모의 테스트는 방법 2 와 유사합니다 . MyClass 인스턴스가 예외를 발생시키기를 원합니다. mock.side_effect와 mock.return_value.side_effect를 모두 시도했지만 작동하지 않았습니다. 어떡하죠?
Hussain

5
@ D.Shawley 링크가 끊어졌습니다. 지금 여기에서 찾을 수 있습니다. "패치 할 위치"
RazerM

2
클래스 객체 를 패치하려면 stackoverflow.com/questions/8469680/…을
storm_m2138

27

이것에 대한 YouTube 비디오 가 있습니다.

짧은 대답 : mock조롱하고 싶은 것을 전달할 때 사용 하고 patch그렇지 않은 경우 사용하십시오. 두 가지 중에서 mock은 적절한 종속성 주입으로 코드를 작성하고 있음을 의미하기 때문에 강력하게 선호됩니다.

어리석은 예 :

# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
    sentence.replace('cks','x')   # We're cool and hip.
    twitter_api.send(sentence)

# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class 
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
    twitter_api = Twitter(user="XXX", password="YYY")
    sentence.replace('cks','x') 
    twitter_api.send(sentence)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.