Ein Hinweis zu Mock (Python-Mock-Bibliothek)

Ich habe die Scheinbibliothek vorher nicht richtig benutzt, also habe ich einige Nachforschungen angestellt.

Scheininstallation

Es gibt mehrere Python-Mock-Bibliotheken, aber dieses Mal werde ich mock verwenden. In Python 3.3 oder höher ist es Standard Library und beim Schreiben eines Programms, das nur 3.3 oder höher unterstützt Muss keine externe Bibliothek installieren. Tatsächlich scheint es viele Fälle zu geben, in denen es erst nach 3.3 nicht mehr unterstützt wird. Wird es also üblich sein, mit pip zu installieren?

Scheininstallation


$ pip install mock

Durch Schein ersetzen

Der Punkt ist die mock.Mock-Klasse. Eine Instanz der Mock-Klasse kann aufgerufen werden, und Sie können den Rückgabewert beim Aufrufen festlegen.

Rückgabewerteinstellung


>>> from mock import Mock
>>> m = Mock()
# return_Legen Sie den Rückgabewert im Wertattribut fest
>>> m.return_value = 5
>>> m()
5

Ersetzen Sie die Mock-Instanz durch den auf diese Weise festgelegten Rückgabewert durch die tatsächlich verarbeitete Klassenmethode. Das meiste, was Sie tun, ist dies.

Ein Beispiel wird mit dem folgenden Code gezeigt. Im folgenden Code hängt B # b_test von der Verarbeitung von A # a_test ab. Was ist, wenn ich B # b_test alleine testen möchte?

B#b_Test und A.#a_Testabhängigkeit


class A(object):
    def a_test(self):
        print('test')

class B(object):
    def __init__(self, a_ins):
        self.a_ins = a_ins
    def b_test(self):
        return self.a_ins.a_test()

In diesem Fall kann die Abhängigkeit getrennt werden, indem A # a_test durch die Mock-Instanz ersetzt wird.

Ersatz zum Verspotten


>>> a = A()
>>> a.a_test = Mock()
>>> a.a_test.return_value = 'mocked'
>>> b = B(a)
>>> b.b_test()
'mocked'

Im obigen Beispiel wird die Methode ersetzt. In vielen Fällen möchten Sie jedoch die gesamte Methode auf Instanzbasis und nicht auf Methodenbasis ersetzen. Geben Sie in diesem Fall beim Erstellen einer Mock-Instanz die Klasse an, die Sie im Argument spec verspotten möchten.

Ersatz zum Verspotten(Verwenden Sie spec)


>>> a = Mock(spec=A)
>>> a.a_test.return_value = 'mocked_spec'
>>> b = B(a)
>>> b.b_test()
'mocked_spec'

Mock-Aufrufe werden in der Mock-Instanz aufgezeichnet. Mit diesen Informationen können Sie die Beziehungen zwischen Instanzen überprüfen (= ob der Aufruf korrekt ist).

Aufzeichnung eines Scheinanrufs


>>> a = Mock(spec=A)
>>> a.a_test.return_value = 'mocked_spec'
>>> b = B(a)
# Mock#call_args_list:Liste zum Speichern von Aufrufen für diese Mock-Instanz
>>> a.a_test.call_args_list
[]

# Mock#assert_any_call:Bestätigen Sie, ob der entsprechende Mock-Instanzaufruf in der Vergangenheit war.
#In diesem Beispiel gibt es kein Argument, aber in Wirklichkeit ist es möglich, ein beliebiges Argument anzugeben(Geben Sie an, ob mit diesem Argument ein Mock-Instanzaufruf aufgetreten ist)
# (ref. http://www.voidspace.org.uk/python/mock/mock.html)
>>> a.a_test.assert_any_call()
Traceback (most recent call last):
  File "<ipython-input-81-ed526bd5ddf7>", line 1, in <module>
    a.a_test.assert_any_call()
  File "/Users/tatsuro/.venv/py3.3/lib/python3.3/site-packages/mock.py", line 891, in assert_any_call
    '%s call not found' % expected_string
AssertionError: a_test() call not found

>>> b.b_test()
'mocked_spec'

# B#b_test()Angerufen über
>>> a.a_test.call_args_list
[call()]
>>> a.a_test.assert_any_call()
>>>

Verspotten Sie den Vorgang der Rückgabe einer Ausnahme

Wenn Sie einen Rückgabewert zurückgeben möchten, können Sie ihn auf "return_value" setzen. Was ist jedoch, wenn Sie den Vorgang des Auslösens einer Ausnahme wie unten gezeigt verspotten möchten?

Verarbeitung, um eine Ausnahme auszulösen


class A(object):
    def a_test(self):
        raise ValueError

class B(object):
    def __init__(self, a_ins):
        self.a_ins = a_ins
    def b_test(self):
        try:
            return self.a_ins.a_test()
        except ValueError:
            print('error handling')

Verwenden Sie in diesem Fall Mock # side_effect. Wenn Sie hier eine Ausnahme festlegen, können Sie eine Ausnahme auslösen, wenn Sie den Mock aufrufen.

side_Schein-Ausnahmebehandlung durch Effekt


>>> a = Mock(spec=A)
>>> a.a_test.side_effect = ValueError
>>> b = B(a)
>>> b.b_test()
error handling

Hier wird die Ausnahmebehandlung als häufiger Anwendungsfall erwähnt, aber side_effect ist nicht auf die Ausnahmebehandlung spezialisiert. Es ist ein Mechanismus zum "Hinzufügen der erforderlichen Logik beim Aufrufen einer Mock-Instanz", und es ist auch möglich, eine Verarbeitung nur zu einem bestimmten Argument hinzuzufügen und als Rückgabewert zu verwenden, wie unten gezeigt.

Fügen Sie je nach Argument eine andere Verarbeitung hinzu


>>> class B(object):
    def __init__(self, a_ins):
        self.a_ins = a_ins
    def b_test(self, value):
        try:
            return self.a_ins.a_test(value)
        except ValueError:
            print('error handling')

>>> def handler(value):
    if (value % 2) == 0:
        return value * 2
    return value

>>> a.a_test.side_effect = handler
>>> b = B(a)
>>> b.b_test(1)
1
>>> b.b_test(2)
4
>>> b.b_test(3)
3

Das Einbeziehen einer zu komplizierten Logik in side_effect scheint jedoch aus Wartungssicht nicht vorzuziehen zu sein. Wenn die Logik kompliziert wird, müssen möglicherweise Maßnahmen wie das Teilen des Testfalls ergriffen werden.

Aktivieren Sie Mock in einem bestimmten Bereich

mock hat einen Mechanismus namens "patch", der das Verspotten nur in einem bestimmten Bereich ermöglicht. patch kann in Funktionsaufrufen verwendet werden, kann aber auch als Kontextmanager oder Dekorateur behandelt werden. In vielen Fällen wird es hier behandelt.

Ein Beispiel für die Behandlung als Kontextmanager ist wie folgt. Sie können das Modell mit dem Namen behandeln, der nach als angegeben ist.

Behandle Patch als Kontextmanager


>>> class C(object):
    def hoge(self):
        return 'hoge'

#Klasse C verspotten nur mit Geltungsbereich unter der with-Anweisung(CMock)Kann verwendet werden
>>> with patch('__main__.C') as CMock:
    c = CMock()
    c.hoge.return_value = 'test'
    print(c.hoge())
...
test

Wenn Sie es als Dekorateur behandeln, ist es wie folgt. Ein Mock wird als letztes Argument der dekorierten Funktion übergeben.

Behandle Patch als Dekorateur für eine Funktion


>>> @patch('__main__.C')
    def patched_func(CMock):
        c = CMock()
        c.hoge.return_value = 'test'
        print(c.hoge())
...
>>> patched_func()
test

Es kann nicht nur als Dekorateur für eine Funktion, sondern auch als Dekorateur für eine Klasse behandelt werden. Viele Testwerkzeuge können Testfälle in Klassen gruppieren (unter der Annahme = 1 Testfall / 1 Methode), sodass auf alle Tests ein gemeinsames Modell angewendet werden kann. Zu diesem Zeitpunkt muss auf das Vorhandensein von "patch.TEST_PREFIX" geachtet werden. Wenn Sie einen Dekorator für die Klasse angeben, wird der Mock nur für Methoden übergeben, die mit patch.TEST_PREFIX beginnen. Daher ist es notwendig, die Testmethode gemäß einer bestimmten Namensregel zu implementieren. (Aber der Standardwert ist'test ', also mach dir keine Sorgen?)

Behandle Patch als Dekorateur für eine Klasse


#Mock wird nur an Methoden mit diesem Präfix übergeben.
>>> patch.TEST_PREFIX
'test'

>>> @patch('__main__.C')
class CTest(object):
    def test_c(self, CMock):
        c = CMock()
        c.hoge.return_value = 'hoge_test'
        print(c.hoge())

    def notmock(self, CMock):
        pass
...
# 'test'Methoden, die mit beginnen. Ein Schein wird übergeben.
>>> CTest().test_c()
hoge_test

# 'test'Eine Methode, die nicht mit beginnt. Da der Mock nicht übergeben wird, tritt aufgrund unzureichender Argumente ein Fehler auf.
>>> CTest().notmock()
Traceback (most recent call last):
  File "<ipython-input-189-cee8cb83c7b4>", line 1, in <module>
    CTest().notmock()
TypeError: notmock() missing 1 required positional argument: 'CMock'

Recommended Posts

Ein Hinweis zu Mock (Python-Mock-Bibliothek)
Ein Memorandum über den Python-Mock
Ein Hinweis zu [Python] __debug__
Python: Ein Hinweis zu Klasse 1 "Abstract"
Ein Hinweis zu __call__
Ein Hinweis zum Unterprozess
Ein Hinweis zu mprotect (2)
Schreiben Sie eine Notiz über die Python-Version von Python Virtualenv
Ein Memorandum über die Python-Tesseract-Wrapper-Bibliothek
Ein Hinweis zu KornShell (ksh)
Memorandum über Korrelation [Python]
Ein Hinweis zur TensorFlow-Einführung
Verwenden Sie Pymol als Python-Bibliothek
Python Hinweis: Über den Vergleich mit is
Ein Hinweis zum Aufrufen der Facebook-API mit dem Python SDK
Hinweis zu get_scorer von sklearn
Hinweis: Python
Python-Notiz
Generieren Sie das Display-Abzeichen für die Download-Anzahl der Python-Bibliotheken
Über psd-tools, eine Bibliothek, die psd-Dateien in Python verarbeiten kann
Nachdem ich die Python-Bibliothek recherchiert hatte, verstand ich ein wenig über ei.info.
Eine Notiz, in der ein Python-Anfänger stecken blieb
Ein Java-Programmierer studierte Python. (Über Typ)
Über den 02. Februar 2020 * Dies ist ein Python-Artikel.
Ein Memo, dass ich das Pyramid Tutorial ausprobiert habe
Python 3.6 E-Mail-Bibliothek
Über die Einschlussnotation von Python
Python lernen note_002
Hinweis: Python-Dekorator
Python-Programmierhinweis
[Python] Lernnotiz 1
Python ast Bibliothek
Über Python tqdm.
Über die Python-Ausbeute
Python lernen note_004
Versuchen Sie es mit APSW, einer Python-Bibliothek, die SQLite ernst nehmen kann
Informationen zur Python-Vererbung
Über Python, range ()
Python lernen note_003
Python Library Hinweis
Über Python Decorator
Ein Hinweis zu den Funktionen der Standard-Linux-Bibliothek, die sich mit Zeit befasst
[Hinweis] openCV + Python
Hinweis zu awk
Informationen zur Python-Referenz
Über Python-Dekorateure
[Python] Über Multi-Prozess
Python-Anfängernotiz
Ein Java-Programmierer studierte Python. (Über Funktionen (Methoden))
Ein Java-Programmierer studierte Python. (Über Dekorateure)
[Hinweis] Erstellen Sie mit Python eine einzeilige Zeitzonenklasse
Ein Memo, das ich in Python zusammengeführt habe
Einfache Pub / Sub-Programmhinweise in Python
Python Hinweis: Wenn Sie einer Zeichenfolge einen Wert zuweisen
Eine Geschichte über das Ausführen von Python auf PHP auf Heroku
Denken Sie daran, eine Python 3-Umgebung in einer Mac-Umgebung zu erstellen
[Hinweis] Über die Rolle des Unterstrichs "_" in Python
Modifikatoren zur Überprüfung von Memos mit MaxPlus
Eine Geschichte über das Ändern von Python und das Hinzufügen von Funktionen
Über Python für Schleife