Mock vs MagicMock

138

Mein Verständnis ist, dass MagicMock eine Obermenge von Mock ist , die automatisch "magische Methoden" ausführt und so Listen, Iterationen usw. nahtlos unterstützt ... Was ist dann der Grund für das Vorhandensein von einfachem Mock ? Ist das nicht nur eine abgespeckte Version von MagicMock , die praktisch ignoriert werden kann? Kennt die Mock- Klasse Tricks, die in MagicMock nicht verfügbar sind ?

Vladimir Ignatov
quelle

Antworten:

99

Was ist der Grund für das Vorhandensein von Mock ?

Mocks Autor Michael Foord ging auf der Pycon 2011 (31:00) auf eine sehr ähnliche Frage ein :

F: Warum wurde MagicMock separat erstellt, anstatt die Fähigkeit nur in das Standard-Scheinobjekt zu falten?

A: Eine vernünftige Antwort ist, dass MagicMock so funktioniert, dass alle diese Protokollmethoden vorkonfiguriert werden, indem neue Mocks erstellt und festgelegt werden. Wenn also jeder neue Mock eine Reihe neuer Mocks erstellt und diese als Protokollmethoden und dann alle diese Protokolle festlegt Methoden haben eine Menge mehr Mocks erstellt und sie auf ihre Protokollmethoden gesetzt. Sie haben eine unendliche Rekursion ...

Was ist, wenn der Zugriff auf Ihr Modell als Containerobjekt ein Fehler sein soll - Sie möchten nicht, dass dies funktioniert? Wenn jeder Mock automatisch jede Protokollmethode hat, wird es viel schwieriger, dies zu tun. Außerdem übernimmt MagicMock einige dieser Vorkonfigurationen für Sie und legt Rückgabewerte fest, die möglicherweise nicht angemessen sind. Daher dachte ich, es wäre besser, diese Bequemlichkeit zu haben, bei der alles vorkonfiguriert und für Sie verfügbar ist, aber Sie können auch ein gewöhnliches Modell erstellen Objekt und konfigurieren Sie einfach die magischen Methoden, die Sie existieren möchten ...

Die einfache Antwort lautet: Verwenden Sie MagicMock einfach überall, wenn Sie dies wünschen.

Ryne Everett
quelle
11
Ich denke, eine bessere Antwort ist: Verwenden Sie MagicMock, wenn Sie wissen, was Sie tun, andernfalls verwenden Sie Mock.
laike9m
55

Mit Mock Sie können magische Methoden verspotten , aber man muss sie definieren. MagicMock verfügt über "Standardimplementierungen der meisten magischen Methoden". .

Wenn Sie keine magischen Methoden testen müssen, ist Mock ausreichend und bringt nicht viele irrelevante Dinge in Ihre Tests ein. Wenn Sie viele magische Methoden testen müssen, spart Ihnen MagicMock einige Zeit.

Sean Redmond
quelle
Klar habe ich die Dokumentation schon gelesen. Das beantwortet meine Frage nicht - warum sollte man sich mit Mock beschäftigen, wenn MagicMock genau das Gleiche tut und noch viel mehr? Ich sehe in meinen Tests keine fremden Dinge - benutze einfach den anderen Namen und das war's. Wo ist also der Haken?
Vladimir Ignatov
39
Tests sollten minimal sein und Scheinobjekte sollten minimal funktionsfähig sein, damit Sie genau wissen, was Sie testen. Wenn Sie MagicMock verwenden, nur weil es mehr bewirkt, aber nicht explizit all das "Mehr" testet, besteht das Risiko, dass ein Test aufgrund eines standardmäßigen MagicMock-Verhaltens fehlschlägt. Dieser Fehler spiegelt möglicherweise mehr die Standardeinstellungen von MagicMock wider als das, worüber es sich lustig machen soll. Schlimmer noch, Sie laufen Gefahr, dass ein Test erfolgreich ist, wenn er fehlgeschlagen sein sollte. Das Risiko ist gering, aber wenn dies passiert, wird es viel Zeit verschwenden.
Sean Redmond
1
Ich denke, es ist so, als würde man einfaches JS gegen Jquery verwenden. Sicher, Sie könnten Jquery verwenden, um alle Ihre JS zu erledigen, aber in einigen Fällen möchten Sie nur das minimale Tool verwenden, das erforderlich ist, um die Arbeit zu erledigen. Ich finde, dass diese Fälle normalerweise entweder extrem einfach oder extrem komplex sind.
kuschelt
49

Zunächst MagicMockist eine Unterklasse von Mock.

class MagicMock(MagicMixin, Mock)

Als Ergebnis bietet MagicMock alles, was Mock bietet, und mehr. Anstatt Mock als eine abgespeckte Version von MagicMock zu betrachten, sollten Sie sich MagicMock als eine erweiterte Version von Mock vorstellen. Dies sollte Ihre Fragen dazu beantworten, warum Mock existiert und was Mock zusätzlich zu MagicMock bietet.

Zweitens bietet MagicMock Standardimplementierungen vieler / der meisten magischen Methoden, während Mock dies nicht tut. Sehen Sie hier für weitere Informationen über die magischen Methoden zur Verfügung gestellt.

Einige Beispiele für bereitgestellte magische Methoden:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

Und diese, die möglicherweise nicht so intuitiv sind (zumindest für mich nicht intuitiv):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

Sie können die zu MagicMock hinzugefügten Methoden "sehen", wenn diese Methoden zum ersten Mal aufgerufen werden:

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

Warum also nicht immer MagicMock verwenden?

Die Frage an Sie lautet: Sind Sie mit den Standardimplementierungen der magischen Methode einverstanden? Ist es zum Beispiel in Ordnung mocked_object[1], keinen Fehler zu machen? Sind Sie mit unbeabsichtigten Konsequenzen einverstanden, da die Implementierungen der magischen Methode bereits vorhanden sind?

Wenn die Antwort auf diese Fragen Ja lautet, verwenden Sie MagicMock. Ansonsten bleib bei Mock.

user650654
quelle
12

Dies ist, was Python offizielle Dokumentation sagt:

In den meisten dieser Beispiele sind die Klassen Mock und MagicMock austauschbar. Da der MagicMock die leistungsfähigere Klasse ist, ist es sinnvoll, ihn standardmäßig zu verwenden.

user2916464
quelle
3

Ich habe einen anderen speziellen Fall gefunden, in dem einfach Mock nützlicher sein kann als MagicMock:

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

Ein Vergleich mit ANYkann beispielsweise nützlich sein, um fast jeden Schlüssel zwischen zwei Wörterbüchern zu vergleichen, bei denen ein Wert mithilfe eines Modells berechnet wird.

Dies gilt, wenn Sie Folgendes verwenden Mock:


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

während es ein erhöht, AssertionErrorwenn Sie verwendet habenMagicMock

Manu
quelle