Um ein System zu testen, isolieren Sie die Nebenwirkungen

Das Entfernen von Nebenwirkungen ist eine der besten Möglichkeiten, testbaren Code zu erstellen

Das Bild eines Boxkampfes zwischen zwei männlichen Kämpfern. Ihre Gesichter sind außerhalb des Rahmens. Der Kämpfer links hat einen linken Haken an den Kämpfer rechts geschickt. Der Kämpfer auf der rechten Seite trägt eine rote Shorts mit einem kleinen Symbol der Sowjetunion.

Nock ist eine berühmte Bibliothek, die in JavaScript geschrieben ist und sich für Stub-Netzwerkanforderungen eignet. Es gibt eine statische Antwort für die Tests zurück, damit diese ausgeführt werden können, auch wenn kein HTTP-Server verfügbar ist.

Es ist jedoch auch ein Geruch.

Die resultierende Kopplung zwischen der Datenquelle und dem getesteten System verursacht Kosten, die sich auf das Refactoring und die Wartbarkeit des Codes auswirken können.

Hier ist der Grund.

Angenommen, es gibt einen Server, der eine Liste von Posts zurückgibt, und eine Funktion, die die Antwort dieses Servers verwendet, um eine Liste von Post-Titeln zu erstellen. Der Test für die Funktion verwendet Nock, um die Antwort vom Server zu stoppen:

Ein Diagramm, das links einen Block mit der Überschrift

Der Code hat eine anständige Abdeckung. Es gibt jedoch einige Probleme.

Wenn Sie den Inhaltstyp der Antwort ändern, müssen Sie die Tests ändern, auch wenn das Verhalten des Codes unverändert bleibt:

Gleiches gilt, wenn Sie Änderungen an der URL, den Headern oder den Parametern vornehmen, die Nock stubbt. Sie müssen die Tests ändern, auch wenn das Verhalten des Systems gleich bleibt:

Die Funktion "Liste der Beiträge erstellen" ist das zu testende System (SUT). Die Daten aus dem HTTP-Aufruf sind die Datenquelle.

Sie können den Code so gestalten, dass die Datenquelle über eine allgemeine Schnittstelle verfügt, die mit dem SUT verbunden werden kann. In diesem Fall können Sie die Logik üben, ohne zu viele Einstellungen vornehmen zu müssen.

Ein Diagramm, das links einen Block mit der Überschrift

In einer Testumgebung können Sie eine "In-Memory-Datenquelle" einfügen. Für die Produktion können Sie die "HTTP-Server-Datenquelle" verwenden.

Die "allgemeine Schnittstelle" in der vorherigen JSFiddle-Version ist die Methode "Posts-Titel suchen". Unabhängig davon, wie Sie die Schnittstelle erstellen, haben Sie die Kontrolle über alle Aufrufer. Änderungen sind daher unkompliziert. Martin Fowler nennt das eine "nicht veröffentlichte Schnittstelle".

Wenn der Server dagegen den Vertrag für die veröffentlichte Schnittstelle bricht und das Klassenattribut sich von Posttitel zu Artikeltitel ändert, müssen Sie nur die Datenquellenimplementierung ändern. Sie müssen nicht überall Änderungen vornehmen.

Was wichtig ist, um zu testen und frühzeitiges Feedback zu erhalten, sind Tests gegen das Verhalten, nicht gegen die Daten. Daher ist es wichtig, den Code so zu gestalten, dass weniger Aufwand für Änderungen an der Logik anfällt. In diesem Fall ist die Logik die Transformation der Eingabe von der Datenquelle in die ungeordnete HTML-Liste.

Mit dem neuen Design haben Sie die Datenquelle vom getesteten System abgekoppelt. Daher können Sie Nock entfernen.

Das neue Design reduziert auch die Arbeit, die erforderlich ist, um dem System eine neue Regel ohne Kopieren / Einfügen hinzuzufügen:

Die "HTTP-Server-Datenquelle" verfügt jedoch über eine ungetestete Logik in der privaten Funktion "Titel von Posts in HTML abfragen".

Um dies zu testen, können Sie dasselbe Muster wiederholen. Schieben Sie die Nebenwirkungen und machen Sie den "Get Request" -Mechanismus steckbar in die "HTTP Server Data Source". So können Sie den Code auch ohne Nock testen:

Da Sie bereits Tests zur Bestätigung haben, dass der Titel der "Liste der Beiträge" mit einer "In-Memory-Datenquelle" funktioniert, können Sie die Datenquelle auch einzeln testen, um sicherzustellen, dass sie das richtige Ergebnis zurückgibt:

Sie haben den Nebeneffekt vollständig aus der Logik verdrängt. In diesem Fall ist die eigentliche Funktion "Get Request" der Nebeneffekt. Jetzt können Sie Nock verwenden, um das zu decken.

Da die Logik in der "Get-Anfrage" jedoch trivial ist und Nock erhebliche Kosten verursacht, ist es sinnvoll, eine kleine Anzahl von Integrationstests durchzuführen, mit denen die gesamte Anwendung, einschließlich der Nebenwirkungen, ausgeführt werden kann. Sie können Nock verwenden, um die Verbindung zu einem Live-Server zu vermeiden, und dennoch HTTP-Anforderungen verwenden, um zu überprüfen, ob die Anwendung eine angemessene Antwort zurückgibt, wenn alle Teile zusammenpassen.

Nock ist nützlich, um die Verbindung in der HTTP-Schicht zu unterbrechen und eine statische Antwort bereitzustellen. Verwenden Sie es jedoch sparsam. Mit jedem Test, den Sie durchführen, erhöhen Sie die Kopplung und die Änderungskosten erheblich.

Wenn es nicht sparsam verwendet wird, kann Nock eine Nockhölle erschaffen.

Das Problem, das Sie lösen möchten, besteht darin, die Anzahl der Fehler und die Kosten für Änderungen zu verringern. Wenn Sie die Struktur des Codes ändern, ohne das Verhalten zu ändern, sollten die Tests nicht unterbrochen werden. Wenn ja, haben Sie keine nützlichen Tests geschrieben.

Ihr Ziel sollte es sein, die Qualität der Testabdeckung entsprechend der von Ihnen gewünschten Logik zu verbessern und frühzeitiges Feedback zu erhalten. Das alles, ohne dass Sie dadurch die Möglichkeit haben, den Code zu überarbeiten.

Isolieren Sie Nebenwirkungen und beschränken Sie den Einsatz von Tools wie Nock auf die Grenzen der Anwendung.

Das sollte dir genug Selbstvertrauen geben, um Änderungen vorzunehmen und keine Dinge zu zerstören.

Kämpfen Sie mit, lindern Sie die Nebenwirkungen und dann ... Nocken Sie es aus.

Danke fürs Lesen. Wenn Sie Feedback haben, wenden Sie sich an mich auf Twitter, Facebook oder Github.

Vielen Dank an Eduardo Slompo und Guilherme J. Tramontina für ihr aufschlussreiches Feedback zu diesem Beitrag.