[PYTHON] So führen Sie einen Komponententest durch Teil 2 Klassendesign zum Testen

Einführung

In einer Reihe von Artikeln in diesem Titel werden Implementierungen zum Testen und Produzieren unter Verwendung von Entwurfsmustern betrachtet. Im vorherigen Artikel (http://qiita.com/progrommer/items/a04a74d8b9f43eaef4b9) habe ich das Proxy-Muster und das Monostate-Muster vorgestellt, die grundlegende Konzepte und benutzerfreundliche Formen aufweisen. Dieses Mal werde ich beschreiben, wie die zu testende Klasse entworfen wird. Nach dem letzten Mal lautet das Thema Dependency Injection (DI).

Das Beispielprogramm ist eine Mischung aus Python, C # und C ++, aber wir planen, es zu gegebener Zeit zu ergänzen. Bitte verzeih mir.

Trennung von Erzeugung und Nutzung

Gleicher Ort für Erzeugung und Verwendung

Einige schwer zu testende Klassen- (oder Funktions-) Implementierungen werden an derselben Stelle erstellt und verwendet.

// Python
class Some:
    def get(self):
        return 42

def func():
    some = Some()
    value = some.get()
    if value < 10:
        pass
// C++
struct Some {
    int get() const {return 42;}
};

void func() {
    if (Some().get() < 10) return;
}

In diesem Beispiel wird eine Instanz der Klasse Some im laufenden Betrieb erstellt und die Funktion aufgerufen. Dies macht es unmöglich, in Some einzugreifen, selbst wenn Sie versuchen, die Funktionsfunktion zu testen.

Ein anderes Beispiel

Es ist auch wichtig, den Fall zu beachten, in dem ein Element vom Konstruktor generiert und dann von einer beliebigen Funktion verwendet wird. Im folgenden Beispiel kann der Testcode der Zielklasse m_some nach dem Generieren von Some ersetzen, und es besteht Raum für Eingriffe. Auf den ersten Blick sieht das gut aus. Wenn Sie jedoch Some aus einer anderen Klasse oder Funktion aufrufen, können Sie diese Klasse oder Funktion nicht testen.

// C++
Target::Target()
  : m_some(new Some("abc"))
{
}

Target::exec() {
    m_some->get();
}

//Eine weitere zu testende Funktion
void func() {
    Target target;
    target.exec();  //Original Einige werden in Target generiert und verwendet
}

Verwenden Sie Muster zur Generierung

Wenn die oben erwähnte feste Erzeugung und Verwendung durchgeführt wird, wird der Einheitentest schwierig. Sobald auch nur eine solche Klasse erstellt wurde, ist es schwierig, sie zu entwirren. Aus diesem Grund ist es wünschenswert, die Klasse zu entwerfen, indem Erzeugung und Verwendung von der frühesten Stufe getrennt werden. Es gibt verschiedene Möglichkeiten, dies zu tun, aber hier sind einige Beispiele, die tatsächlich einfach zu verwenden sind.

Abstraktes Fabrikbeispiel

Das Entwurfsmuster enthält mehrere "Generierungs" -Muster, aber verwenden wir eines davon, das abstrakte Fabrikmuster.

AbstractFactory.png

Im folgenden Beispiel verwendet die Benutzer-Client-Klasse einen Generator namens Creator. Sie erstellen die benötigten Logger- und File-Instanzen aus der Creator-Instanz, die Sie erhalten haben. Die Substanz von Creator ist TestCreator, das in main () erstellt wurde. Es wurde durch eine Testklasse ersetzt, die an die Konsole ausgegeben und eine Dummy-Datei generiert wird.

Klassenname in der Abbildung Beispielklassenname
ICreator Creator
TargetCreator Keiner
Target1 Logger
Target2 File
Target1Object Keiner
Target2Object Keiner
ClientTest Hauptfunktion
DummyCreator TestCreator
Dummy1Object ConsoleLogger
Dummy2Object DummyFile
# Python
class Logger:
    def write(self, msg: str) -> None:
        pass

class ConsoleLogger(Logger):
    def write(self, msg: str) -> None:
        print(msg)

class File:
    pass

class DummyFile(File):
    pass

class Creator:
    def create_logger(self) -> Logger:
        return None
    def create_file(self) -> File:
        return None

class TestCreator(Creator):
    def create_logger(self) -> Logger:
        return ConsoleLogger()
    def create_file(self) -> File:
        return DummyFile()

class Client:
    def __init__(self, creator: Creator):
        self._logger = creator.create_logger()
        self._file = creator.create_file()
    def exec(self) -> None:
        #Etwas zu verarbeiten
        self._logger.write('Erfolgreiche Fertigstellung')

def main():
    creator = TestCreator()
    client = Client(creator)

    client.exec()

Singleton Beispiel

Ein weiteres Beispiel für ein "Generierungs" -Muster ist Singleton. Singleton kann nicht eingreifen, da die Generation innerhalb ihrer Klasse geschlossen ist. Der Zweck besteht darin, nicht eingreifen zu können, aber es ist schwierig, ihn zum Testen zu verwenden.

Hier lockern wir die Struktur von Singleton ein wenig und bereiten einen Mund für die Intervention vor. Die Instanz ist geschützt und alle Methoden verwenden entweder NVI oder nur virtuell.

Singleton1.png

Das folgende Beispiel zeigt das Ersetzen der Singleton-Klasse und der Testklasse in C #. Der zweite Aufruf von Print (), der zu Dummy wechselt, gibt "Dummy" für dieselbe Methode aus. Zum Zeitpunkt des Unit-Tests sollte es im Vorbereitungsprozess eingestellt werden, damit Dummy von Anfang an aufgerufen wird.

// C#
public class Some {
    protected static Some instance;
    static Some() {
        instance = new Some();
    }
    static public Some getInstance() {
        return instance;
    }
    virtual public void Print() {
        Console.WriteLine("Some");
    }
}

internal class SomeDummy : Some {
    internal static void UseDummy() {
        instance = new SomeDummy();
    }
    public override void Print() {
        Console.WriteLine("Dummy");
    }
}

public class Client {
    static void Main(string[] args) {
        {
            var target = Some.getInstance();
            target.Print();    // "Some"Und Ausgabe
        }

        SomeDummy.UseDummy();  //Ersetzen Sie Singleton
        {
            var target = Some.getInstance();
            target.Print();    // "Dummy"Und Ausgabe
        }
    }
}

Anwendung

Abstrakte Fabrik kann ärgerlich sein, weil sie die Fabrik bei der Klassengenerierung passieren muss. Anwendungen wie die Bereitstellung einer Fabrik mit Singleton oder Monostate können in Betracht gezogen werden. Geben Sie zum Zeitpunkt des Komponententests natürlich eine Fabrik zurück, die eine Dummy-Klasse zum Testen generiert. Verwenden Sie dies, um das erste Beispiel zu ersetzen:

// Python
class FactoryServer:
    some_creator = SomeCreator()

def func():
    some = FactoryServer.some_creator()
    value = some.get()
    if value < 10:
        pass

Zusammenfassung

Ein Beispiel für die Trennung von Erzeugung und Verwendung wird gezeigt.

Im Beispiel der Abstract-Factory haben wir eine Struktur gezeigt, in der die tatsächliche Klasse und die Klasse für Unit-Tests frei ersetzt werden können, indem das Objekt sowohl für die Erstellung als auch für die Verwendung abstrahiert wird. Im Singleton-Beispiel wurde das Produkt eingegriffen, um eine Testinstanz zu verwenden. Als Anwendung haben wir durch die Kombination von Singleton / Monostate und Abstract Factory eine Konfiguration angegeben, in der Testinterventionen gleichzeitig eingerichtet werden können, während die Einfachheit der Implementierung erhalten bleibt.

Andere

Recommended Posts

So führen Sie einen Komponententest durch Teil 2 Klassendesign zum Testen
So führen Sie einen Komponententest durch Teil 1 Entwurfsmuster zur Einführung
[Python] Wie man eine Klasse iterierbar macht
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 2)
[Cocos2d-x] So erstellen Sie eine Skriptbindung (Teil 1)
So erstellen Sie ein Spigot-Plug-In (für Java-Anfänger)
Wie man Python für Anfänger schneller macht [numpy]
Wie man ein Schießspiel mit toio macht (Teil 1)
So erstellen Sie ein Hacking-Labor - Kali Linux (2020.1) VirtualBox 64-Bit Teil 2-
Wie erstelle ich ein Python-Paket (geschrieben für Praktikanten)
[Für Nicht-Programmierer] Wie man Kaggle läuft
Wie man einen lockeren Bot macht
Wie erstelle ich einen Crawler?
So erstellen Sie eine rekursive Funktion
Spigot (Papier) Einführung in die Erstellung eines Plug-Ins für 2020 # 01 (Umgebungskonstruktion)
[Blender] So erstellen Sie ein Blender-Plug-In
[Blender] So erstellen Sie Blender-Skripte mehrsprachig
Wie erstelle ich einen Crawler?
So erstellen Sie mit YOLO in 3 Stunden ein Modell für die Objekterkennung
So machen Sie Word Cloud-Zeichen monochromatisch
Wie man Selen so leicht wie möglich macht
[Einführung in Python] Wie verwende ich eine Klasse in Python?
Verwendung des Entwicklernetzwerks von cybozu.com (Teil 2)
Dekorateur für Unit-Test mit Zufallszahlen
So erstellen Sie eine * .spec-Datei für pyinstaller.
Verwendung von Tweepy ~ Teil 1 ~ [Getting Tweet]
[Python] Organisieren der Verwendung für Anweisungen
Ich habe einen Unit-Test für verschiedene Sprachen geschrieben
So installieren Sie das Windows-Subsystem für Linux
Verwendung von __slots__ in der Python-Klasse
So machen Sie Multi-Boot-USB (Windows 10-kompatibel)
Verwendung von "deque" für Python-Daten
So erstellen Sie einen benutzerdefinierten Backtrader-Indikator
Wie erstelle ich eine Pelican Site Map?
Verwendung der Fingerabdruckauthentifizierung für KDE
[Zur Aufnahme] Keras-Bildsystem Teil 1: Wie erstelle ich einen eigenen Datensatz?
Wie man ein Dialogsystem für Anfänger erstellt
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (11)
So verwenden Sie MkDocs zum ersten Mal
So stellen Sie sicher, dass WTForms TextArea dem Löschen von Dateien entspricht
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (8)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (1)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (4)
So machen Sie mehrere Kernel auf Jupyter auswählbar
Verwendung von Template Engine für Network Engineer
So erstellen Sie ein Wörterbuch mit einer hierarchischen Struktur.
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (7)
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (2)
Wie man eine kratzige JSON-Ausgabe japanisch macht
So erstellen Sie einen eingebetteten Linux-Gerätetreiber (3)
So installieren Sie Python für Forscher von Pharmaunternehmen
Verwendung von Datenanalysetools für Anfänger
Verwendung von Tweepy ~ Teil 2 ~ [Folgen, Gefällt mir usw.]