wake-up-neo.com

Eine Klasse verspotten: Mock () oder Patch ()?

Ich benutze mock with Python und habe mich gefragt, welcher dieser beiden Ansätze besser ist (sprich: mehr Pythonic).

Methode eins : Erstellen Sie einfach ein Scheinobjekt und verwenden Sie dieses. Der Code sieht so aus:

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)

Methode zwei : Verwenden Sie Patch, um ein Mock zu erstellen. Der Code sieht so aus:

@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)

Beide Methoden machen dasselbe. Ich bin mir der Unterschiede nicht sicher.

Könnte mich jemand aufklären?

103
Sardathrion

mock.patch ist ein ganz anderes Lebewesen als mock.Mock. patch ersetzt die Klasse durch ein Scheinobjekt und lässt Sie mit der Scheininstanz arbeiten. Schauen Sie sich diesen Ausschnitt an:

>>> class MyClass(object):
...   def __init__(self):
...     print 'Created [email protected]{0}'.format(id(self))
... 
>>> def create_instance():
...   return MyClass()
... 
>>> x = create_instance()
Created [email protected]
>>> 
>>> @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 [email protected]
<__main__.MyClass object at 0x100505d90>

patch ersetzt MyClass auf eine Weise, mit der Sie die Verwendung der Klasse in von Ihnen aufgerufenen Funktionen steuern können. Sobald Sie eine Klasse patchen, werden Verweise auf die Klasse vollständig durch die Scheininstanz ersetzt.

mock.patch wird normalerweise verwendet, wenn Sie etwas testen, das eine neue Instanz einer Klasse innerhalb des Tests erstellt. mock.Mock Instanzen sind klarer und werden bevorzugt. Wenn dein self.sut.something Methode erstellt eine Instanz von MyClass anstatt eine Instanz als Parameter zu erhalten, dann mock.patch wäre hier angebracht.

141
D.Shawley

Ich habe ein YouTube-Video dazu.

Kurze Antwort: Verwenden Sie mock, wenn Sie das Objekt übergeben, das Sie verspotten möchten, und patch, wenn Sie dies nicht tun. Von den beiden ist Mock stark bevorzugt, da dies bedeutet, dass Sie Code mit der richtigen Abhängigkeitsinjektion schreiben.

Dummes Beispiel:

# 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)
18
MikeTwo