„Wenn ein Arbeiter seine Arbeit gut machen will, muss er zuerst seine Werkzeuge schärfen.“ – Konfuzius, „Die Gespräche des Konfuzius. Lu Linggong“
Titelseite > Programmierung > Verspottung von Python-Klassen

Verspottung von Python-Klassen

Veröffentlicht am 03.11.2024
Durchsuche:767

Mocking Python Classes

In letzter Zeit musste ich Unit-Tests mit Pytest für ein Python-Modul schreiben. Das Modul enthält eine Klasse, in der andere Klassen innerhalb ihres Konstruktors initialisiert werden.

Wie üblich habe ich eine Vorrichtung für diese Klasse erstellt, um das Schreiben eines Tests für jede Klassenmethode zu vereinfachen. Zu diesem Zeitpunkt stieß ich auf einige Probleme, als ich versuchte, die verschiedenen im Konstruktor initiierten Klassen zu verspotten. Das Verspotten funktionierte nicht und es wurden immer noch Instanzen dieser Klassen erstellt.

Nach einigen Recherchen und der Kombination einiger verschiedener Lösungen, die ich online gefunden habe, möchte ich mitteilen, wie ich es geschafft habe, die Klassen nachzuahmen.

Lösung

Hier ist ein Beispiel der Klasse, die ich zu verspotten versuchte:

class ClassA:
    def __init__(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0

Wir möchten bei Tests für jedes Feld dieser Klasse einen Wert festlegen. Dieser Wert kann None oder ein Klassenmock sein, aber wir wollen keine Initiationen der Klassen ClassB und ClassC.

In unserem Fall entscheiden wir, dass self.class_b und self.class_c Mocks sein sollten:

@pytest.fixture
def mock_class_b():
    class_b = Mock(spec=ClassB)
    return class_b

@pytest.fixture
def mock_class_c():
    class_c = Mock(spec=ClassC)
    return class_c

Ein Spielplan für diese Klasse, der unserem Ziel dient, sieht also so aus:

@pytest.fixture
def class_a_mock(mock_class_b, mock_class_c):
    with patch.object(target=ClassA, attribute="__init__", return_value=None) as mock_init:
        class_a = ClassA()
        class_a.class_b = mock_class_b
        class_a.class_c = mock_class_c
        class_b.count = 0
        return class_a

Der wichtige Teil ist die Verwendung der Funktion patch.object, die aus dem Modul unittest.mock in Python stammt. Es wird beim Testen verwendet, um ein Attribut eines bestimmten Objekts vorübergehend durch einen Schein oder einen anderen Wert zu ersetzen.

Argumente

  1. target=ClassA: das Objekt (normalerweise eine Klasse), dessen Attribut wir patchen möchten.
  2. attribute="__init__": der Name des Attributs, das wir patchen möchten.
  3. return_value=None: Ersetzen der __init__-Methode durch eine Funktion, die nichts tut

Auf diese Weise können wir simulierte Variablen in unserem Fixture erstellen.
Lesen Sie mehr über patch.object

Testtipps

Ich habe dieses Tutorial für solche Fälle geschrieben, in denen wir den Code der Klasse A aus irgendeinem Grund nicht ändern können. Ich empfehle jedoch generell, den Code nach Möglichkeit zu ändern, nicht um die Logik zu ändern, sondern um ihn testbarer zu machen .

Hier sind einige Beispiele, wie man Klasse A ändern kann, um sie testbarer zu machen:

Option 1: Übergeben Sie Instanzen von Klasse B und Klasse C als Parameter.
Auf diese Weise können wir beim Schreiben des Fixtures Mocks anstelle von Instanzen übergeben.

class ClassA:
    def __init__(self, class_b_instance, class_c_instance):
        self.class_b = class_b_instance
        self.class_c = class_c_instance
        self.count = 0

Option 2: Erstellen Sie eine boolesche Variable, die den Testmodus angibt.
Auf diese Weise können wir entscheiden, welche Felder der Klasse A bei ihrer Initiierung einen Wert erhalten oder nicht.

class ClassA:
    def __init__(self, test_mode=False):
        if not test_mode:
            self.class_b = ClassB()
            self.class_c = ClassC()
        self.count = 0

Option 3: Klasseninitialisierungen in einer separaten Methode durchführen.
Dieser Ansatz gibt uns die Möglichkeit, den Aufruf von set_class_variables im Testmodul zu vermeiden.

class ClassA:
    def __init__(self):
        self.class_b = None
        self.class_c = None
        self.count = None

    def set_class_variables(self):
        self.class_b = ClassB()
        self.class_c = ClassC()
        self.count = 0

Ich hoffe, das hilft! :)

Freigabeerklärung Dieser Artikel ist abgedruckt unter: https://dev.to/chen_ashkenazi/mocking-python-classes-4h96?1 Bei Verstößen wenden Sie sich bitte an [email protected], um ihn zu löschen
Neuestes Tutorial Mehr>

Haftungsausschluss: Alle bereitgestellten Ressourcen stammen teilweise aus dem Internet. Wenn eine Verletzung Ihres Urheberrechts oder anderer Rechte und Interessen vorliegt, erläutern Sie bitte die detaillierten Gründe und legen Sie einen Nachweis des Urheberrechts oder Ihrer Rechte und Interessen vor und senden Sie ihn dann an die E-Mail-Adresse: [email protected] Wir werden die Angelegenheit so schnell wie möglich für Sie erledigen.

Copyright© 2022 湘ICP备2022001581号-3