Python-Mock-Import

Abid Ullah 21 Juni 2023
  1. Python-Mock-Import
  2. Häufige Fallstricke des Spotts in Python
  3. Grundlegende Verwendung von Mock in Python
  4. So verwenden Sie den Python-Mock-Import
  5. Python-Abhängigkeiten beim Testen
  6. Python-Mock-Objekte
Python-Mock-Import

In diesem Python-Artikel werden wir die mock-Bibliothek untersuchen und lernen, wie man sie effektiv verwendet. Wir beginnen mit einfachen Beispielen und betrachten dann fortgeschrittenere Anwendungen.

Wir werden die Verwendungen und Fallstricke von mock-Objekten und Spott lernen.

Python-Mock-Import

Pythons mock-Bibliothek ist eine der beliebtesten Bibliotheken für Unit-Tests. Es ermöglicht uns, Teile unseres Systems durch Scheinobjekte zu ersetzen und sicherzustellen, dass sie wie erwartet verwendet werden.

Spott ist ein mächtiges Werkzeug, aber es wird oft missverstanden. In diesem Artikel wird erläutert, was Mocking ist, wie es verwendet werden kann und einige häufige Fallstricke.

Spott in Python

Mocking ist der Prozess, ein echtes Objekt durch ein gefälschtes Objekt zu ersetzen. Das gefälschte Objekt wird mock genannt.

Durch Mocking können wir testen, wie unser Code mit anderen Teilen unseres Systems interagiert, ohne tatsächlich von diesen anderen Teilen abhängig zu sein. Zum Beispiel können wir eine Datenbank simulieren, um zu testen, wie unser Code damit interagiert, ohne eine Datenbank zu haben.

So verwenden Sie Mock in Python

Spott kann für zwei verschiedene Zwecke verwendet werden:

  1. Um das Verhalten unseres Codes zu testen

    Sie können beispielsweise eine Datenbank simulieren, um zu bestätigen, dass unser Code sie korrekt abfragt.

  2. Um Verhalten auszublenden, das wir nicht testen wollen

    Beispielsweise könnten wir eine Datenbank simulieren, um eine Verbindung zu ihr zu vermeiden.

Für welchen Zweck wir Mocking verwenden, bestimmt, wie wir es verwenden.

Testverhalten

Wenn wir Mocking verwenden, um das Verhalten zu testen, möchten wir sicherstellen, dass unser Code wie erwartet mit dem Mock-Objekt interagiert. Das Mock-Objekt sollte die gleiche Schnittstelle wie das echte Objekt haben, damit unser Code nicht weiß, dass es sich um ein Mock handelt.

Wir können die Methode assert_called_with() verwenden, um zu bestätigen, dass eine Scheinmethode mit den erwarteten Argumenten aufgerufen wurde. Wenn wir beispielsweise eine Datenbank verspotten, könnten wir behaupten, dass die Methode query() mit dem richtigen SQL aufgerufen wurde.

Wir können auch die Methode assert_called() verwenden, um zu behaupten, dass eine Scheinmethode aufgerufen wurde. Dies ist nützlich, wenn uns die Argumente egal sind oder wenn die Argumente komplex und schwer zu behaupten sind.

Stubbing-Out-Verhalten

Wenn wir Mocking verwenden, um das Verhalten zu unterdrücken, möchten wir das Mock-Objekt so konfigurieren, dass es die erwarteten Werte zurückgibt. Wenn wir beispielsweise eine Datenbank verspotten, können wir die Methode query() so konfigurieren, dass sie eine Liste mit Dummy-Daten zurückgibt.

Wir können das Attribut side_effect verwenden, um ein Mock-Objekt zu konfigurieren. Der Nebeneffekt kann ein beliebiger Wert sein, einschliesslich einer Funktion.

Beim Aufruf des Mocks wird der side_effect zurückgegeben.

Beispielsweise können wir einen side_effect verwenden, um bei jedem Aufruf eines Mocks unterschiedliche Werte zurückzugeben. Dies ist nützlich, um Fehler oder unterschiedliche Verhaltensweisen zu simulieren.

Wir können auch den side_effect verwenden, um eine Ausnahme auszulösen. Dies ist nützlich, um Fehler zu simulieren.

Häufige Fallstricke des Spotts in Python

Es gibt einige häufige Fallstricke bei der Verwendung von Mocking:

  1. Eine Falle ist der Versuch, zu viel zu spotten. Spott ist ein mächtiges Werkzeug, aber kein Allheilmittel.

    Mocking ist am nützlichsten, wenn wir das Verhalten unseres Codes testen, nicht das Verhalten unseres gesamten Systems.

    Wenn wir versuchen, zu viel zu verspotten, werden wir am Ende viele Scheinobjekte haben, und unsere Tests werden schwer zu warten sein. Es ist besser, nur die benötigten Objekte zu verspotten und für den Rest echte Objekte zu verwenden.

  2. Ein weiterer Fallstrick besteht darin, sich zu verspotten, wenn es nicht angebracht ist. Mocking ist am nützlichsten, wenn Sie isolierte Teile Ihres Codes testen.

    Wenn Sie das gesamte System testen, ist es normalerweise besser, Integrationstests zu verwenden. Integrationstests sind Tests, die das gesamte System testen, und sie sind langsamer und teurer in der Ausführung, aber genauer.

  3. Schließlich ist es ein häufiger Fehler, Mocks zu verwenden, wenn wir Fälschungen verwenden sollten. Ein gefälschtes Objekt ist ein Objekt, das ein echtes Objekt imitiert, aber nicht dieselbe Schnittstelle hat.

Beispielsweise kann eine gefälschte Datenbank hartcodierte Daten zurückgeben, anstatt sich mit einer echten Datenbank zu verbinden. Fälschungen helfen, Verhalten zu unterdrücken, aber sie sind nicht so nützlich, um Verhalten zu testen.

Grundlegende Verwendung von Mock in Python

Die grundlegendste Verwendung von Mock besteht darin, ein Objekt durch ein Mock-Objekt zu ersetzen.

Nehmen wir zum Beispiel an, Sie haben eine Funktion, die ein Objekt als Argument nimmt und etwas damit macht. Vielleicht gibt es den Namen des Objekts aus.

Beispielcode:

def print_name(obj):
    print(obj.name)

Wenn wir diese Funktion testen wollten, könnten wir ein Objekt mit einem Namensattribut erstellen und es an die Funktion übergeben.

Beispielcode:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject("Abid")
print_name(obj)

Ausgang:

Abid

Der Code funktioniert und wir können den Namen als Abid gedruckt sehen. Aber es hat ein paar Nachteile.

Erstens müssen wir ein reales Objekt nur zum Testen erstellen. Dies mag in diesem einfachen Beispiel keine große Sache sein, aber in einem komplexeren System kann es eine Menge Arbeit sein, die erforderlichen Objekte nur zum Testen einzurichten.

Zweitens ist dieser Ansatz nicht sehr flexibel. Um verschiedene Verhaltensweisen zu testen, müssen wir jedes Mal ein neues reales Objekt erstellen.

Was ist zum Beispiel, wenn wir testen wollen, was passiert, wenn das Objekt kein Namensattribut hat?

Beispielcode:

class TestObject:
    def __init__(self, name):
        self.name = name


obj = TestObject()
print_name(obj)

Mit dem realen Objekt würden wir einen Fehler erhalten. Bei Verwendung des Testobjekts ist die Ausgabe des Codes jedoch das, was im Code fehlt.

Ausgang:

__init__() missing 1 required positional argument: 'name'

So verwenden Sie den Python-Mock-Import

Um zu Testzwecken mit einem Scheinimport zu arbeiten, erstellen und untersuchen wir ein Scheinobjekt.

Zuerst müssen wir die mock-Bibliothek importieren. Die mock-Bibliothek gibt uns die mock-Klasse, aus der wir unsere Mock-Objekte erstellen können.

Nach dem Import der Bibliothek rufen wir unsere Klasse mock auf und drucken sie aus, um zu sehen, wie dieses Mock-Objekt aussieht.

Beispielcode:

from unittest.mock import Mock

mock = Mock()
print(mock)

Ausgang:

<Mock id='139754809551888'>

Die Ausgabe des Codes zeigt eine Darstellung des Scheinobjekts mit der ID id='139754809551888' Zahlenfolge.

Lassen Sie uns nun untersuchen, was wir mit diesem Scheinobjekt tun und wie wir es verwenden können. Nun, Mock-Objekte werden im Allgemeinen verwendet, um andere Objekte in unserem Code zu patchen.

Wenn wir Patch sagen, bedeutet das ersetzen, imitieren oder verspotten. Sie sind alle gleich.

Denken Sie daran, dass das Wesen des Spotts darin besteht, etwas zu ersetzen, das der Realität so nahe wie möglich kommt. Denken Sie auch daran, dass wir unseren Scheintest in einer kontrollierten Umgebung durchführen möchten.

Externer Anstand führt also nicht dazu, dass unser Scheintest fehlschlägt.

Nehmen wir an, wir haben eine externe Abhängigkeit in unserem Code. Nehmen wir json als Beispiel für externe Abhängigkeit.

Und es ist schwer zu kontrollieren und hat ein Verhalten, das wir in unserem Test nicht unbedingt haben wollen.

Was wir tun können, ist unser Mock-Objekt zu verwenden, um diese Abhängigkeit zu patchen. Zunächst müssen wir also das Dateiformat json importieren.

Dann verwenden wir die Methode json.dumps von JSON und ordnen ihr ein Wörterbuch zu. Wir verwenden also nur eine Methode aus der externen Abhängigkeitsmethode.

Dann patchen wir JSON mit json = mock, und das Mock-Objekt hat kein Dumbs-Objekt. Um dies zu beweisen, müssen wir das Verzeichnis von json drucken.

Beispielcode:

import json

data = json.dumps({"a": 1})
json = mock
print(dir(json))

Ausgang:

['assert_any_call', 'assert_called', 'assert_called_once', 'assert_called_once_with', 'assert_called_with', 'assert_has_calls', 'assert_not_called', 'attach_mock', 'call_args', 'call_args_list', 'call_count', 'called', 'configure_mock', 'dumps', 'getdoc', 'method_calls', 'mock_add_spec', 'mock_calls', 'reset_mock', 'return_value', 'side_effect']

Wir können Zeichenfolgen von Objekten und Methoden als Ausgabe sehen, die dem Scheinobjekt zugeordnet sind. Und beachten Sie, dass dumps keine der Methoden in der Codeausgabe ist.

Python-Abhängigkeiten beim Testen

Wenn eine Funktion, für die wir einen Komponententest schreiben, Abhängigkeiten verwendet, wie z. B. ein request-Modul oder date time. Dann besteht die Möglichkeit, dass unser Komponententest nicht immer die gleiche Ausgabe von der getesteten Funktion erhält.

Nehmen wir an, wir haben eine Funktion, die die Bibliothek request verwendet und einige HTTP-Anfragen stellt. Wenn wir also jetzt unseren Komponententest ohne Internetverbindung ausführen, schlägt er fehl und erhält einen Verbindungsfehler von der request-Bibliothek.

Aus diesem Grund ist es besser, unseren Code in einer kontrollierten Umgebung zu testen, um die Kontrolle über unvorhersehbare Abhängigkeiten zu erlangen, in der wir den tatsächlichen Aufruf einer Abhängigkeit durch ein Scheinobjekt ersetzen können. Dadurch können wir das Verhalten dieser Abhängigkeit optimieren.

Anstatt beispielsweise eine tatsächliche HTTP-Anfrage zu stellen, können wir eine Dummy-HTTP-Antwort bereitstellen, die bei der aufrufenden request.get()-Funktion zurückgegeben wird.

Abhängigkeiten werden auch gespooft, da ein Scheinobjekt Informationen über seine Benutzer enthält, die eingesehen werden können.

Wenn wir beispielsweise angerufen haben, wie oft haben wir angerufen, oder wie oft haben wir eine bestimmte Abhängigkeit angerufen? Dies kann uns also helfen, unsere robusteren Komponententests zu schreiben.

Daher werden wir nun untersuchen, wie Objekte in Python zum Testen verspottet werden.

Python-Mock-Objekte

Wir werden an zwei Python-Skripten arbeiten, um Python-Mock-Objekte besser zu verstehen.

  1. roll_dice_function
  2. mock roll_dice_function

Wir werden also an einem Code arbeiten, der zufällige Werte generiert. Es wird eine einfache roll_dice_function haben, die eine Ganzzahl zwischen einer Zahl und einer anderen zurückgibt.

Und wir werden beide Zahlen an unsere Funktion roll_dice_function übergeben.

Beispielcode:

# import library
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

Also importieren wir zuerst die Bibliothek. Dann definieren wir unsere Funktion mit dem Schlüsselwort def.

Diese Funktion gibt eine ganze Zahl zwischen 5 und 10 zurück. Sie verwendet die Funktion random.randint aus dem Modul random.

Sobald wir mit dem Code von roll_dice_function fertig sind, werden wir einen weiteren Code schreiben, der das Mock-Objekt verwendet, um die roll_dice_function zu testen. Lass uns weitermachen.

Zuerst müssen wir die Testbibliothek für mock importieren.

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)

Mal sehen, wie es funktioniert. Jetzt betrachten wir die Funktionalität der zuvor erstellten roll_dice_function.

Wenn wir also die Funktion aufrufen, erhalten wir eine Zufallszahl von 5 bis 10.

Beispielcode:

# import library
from unittest.mock import Mock
import random

# define function


def roll_dice_function():
    print("The number is....")
    return random.randint(5, 10)


roll_dice_function()

Ausgang:

The number is....
7

Lassen Sie uns den Code erneut ausführen und sehen, welche Zahl wir diesmal erhalten.

Ausgang:

The number is....
5

Jedes Mal, wenn wir die Funktion aufrufen, erhalten wir also eine Zufallszahl zwischen 5 und 10.

Jetzt verwenden wir mock, damit die Funktion bei jedem Aufruf denselben Wert zurückgibt.

Erstellen Sie ein mock-Objekt

Um ein mock-Objekt zu erstellen, müssen wir ein Mock-Klassenobjekt erstellen, das in der mock-Bibliothek definiert ist.

Beispielcode:

mock_roll_object = mock.Mock()

Nun nennen wir das Mock-Objekt mock_roll_object.

mock_roll_object = mock.Mock()
mock_roll_object

Ausgang:

<Mock name='mock.Mock()' id='139883130268416'>

Es zeigt, dass wir beim Aufrufen des Mock-Objekts die Ausgabe als Mock-Objekt erhalten. Das ist also die Sache mit Scheinobjekten im Allgemeinen; Wann immer wir Mock-Objekte aufrufen, erhalten wir ein Mock-Objekt als Ausgabe.

Zur Vereinfachung können wir einige Dinge im Mock-Objekt definieren. Zu Debugging-Zwecken können wir den Namen definieren.

Beispielcode:

mock_roll_object = mock.Mock(name="mocking roll dice")

Wenn wir also versuchen, unseren Komponententest zu debuggen, wird dieser Name möglicherweise angezeigt, was uns beim Debuggen helfen kann.

Ausgang:

<Mock name='mocking roll dice' id='139883130347136'>

Der Name unseres Mocks lautet hier mocking roll dice.

Wenn wir nun einen bestimmten Wert zurückgeben wollen, müssen wir den Wert return_value zuweisen. Wir erhalten also immer dieselbe Nummer, wenn wir das Scheinobjekt aufrufen.

Beispielcode:

mock_roll_object = mock.Mock(name="mocking roll dice", return_value=8)

Jetzt rufen wir das Objekt auf.

mock_roll_object()

Ausgang:

8

Wir erhalten jedes Mal 8, wenn wir das Scheinobjekt aufrufen. Da wir return_value 8 zugewiesen haben, erhalten wir denselben Rückgabewert.

Wir hoffen, dass Sie diesen Python-Artikel hilfreich finden, um zu verstehen, wie Mock in Python verwendet wird.

Autor: Abid Ullah
Abid Ullah avatar Abid Ullah avatar

My name is Abid Ullah, and I am a software engineer. I love writing articles on programming, and my favorite topics are Python, PHP, JavaScript, and Linux. I tend to provide solutions to people in programming problems through my articles. I believe that I can bring a lot to you with my skills, experience, and qualification in technical writing.

LinkedIn

Verwandter Artikel - Python Mock