Abhängigkeitsinjektion und Mocking in funktionalem JavaScript und RxJS

8

Ich versuche eine Bibliothek, die in klassischem OO-Javascript geschrieben wurde, in einen funktionaleren und reaktiveren Ansatz umzuschreiben, indem ich RxJS und Funktionszusammensetzung benutze. Ich habe damit begonnen, zwei leicht überprüfbare Funktionen zu folgen (ich habe den Import von Observablen übersprungen):

create-connection.js

%Vor%

create-channel.js

%Vor%

Alles, was ich tun muss, um sie zu testen, ist, eine Kopie von amqplib oder der Verbindung zu injizieren und sicherzustellen, dass die richtigen Methoden aufgerufen werden, so:

%Vor%

Nun möchte ich die beiden Funktionen wie folgt zusammenfassen:

%Vor%

Allerdings schränkt dies meine Möglichkeiten beim Testen ein, weil ich kein Amikt von amqplib injizieren kann. Ich könnte es vielleicht meinen Funktionsargumenten als eine Abhängigkeit hinzufügen, aber auf diese Weise müsste ich den ganzen Weg in einem Baum zurücklegen und Abhängigkeiten herumreichen, wenn irgendeine andere Zusammensetzung es verwenden wird. Außerdem würde ich gerne in der Lage sein, createConnection und createChannel -Funktionen zu spielen, ohne das gleiche Verhalten testen zu müssen, das ich vorher getestet habe, würde ich meine, dass ich sie als Abhängigkeiten hinzufügen müsste?

Wenn ja, könnte ich eine Factory-Funktion / Klasse mit Abhängigkeiten in meinem Konstruktor haben und dann eine Form der Inversion der Kontrolle verwenden, um sie zu verwalten und sie bei Bedarf einzufügen, was mich jedoch im Wesentlichen dahin zurückbringt, wo ich anfange, was objektorientierter Ansatz ist .

Ich verstehe, dass ich wahrscheinlich etwas falsch mache, aber um ehrlich zu sein habe ich null (null, nada) Tutorials über das Testen von funktionalem JavaScript mit Funktionszusammensetzung gefunden (es sei denn, das ist nicht eins, in welchem ​​Fall was ist).

    
peterstarling 11.08.2017, 13:33
quelle

2 Antworten

4

Kapitel 9 von RxJS in Action steht hier hier zur Verfügung und behandelt das Thema ziemlich gründlich Wenn Sie eine tiefer gehende lesen möchten (vollständige Offenlegung: Ich bin einer der Autoren).

& amp; tldr; Funktionale Programmierung fördert transparente Argumentübergabe. Während Sie also einen guten Schritt hin zu einer kompostierbaren Anwendung gemacht haben, können Sie noch weiter gehen, indem Sie Ihre Nebenwirkungen auf die Außenseite Ihrer Anwendung übertragen.

Wie sieht das in der Praxis aus? Ein Spaßmuster in Javascript ist Funktion currying, das Ihnen erlaubt, Funktionen zu schaffen, die zu anderen Funktionen abbilden. Für Ihr Beispiel könnten wir stattdessen die amqlib-Injektion in ein Argument umwandeln:

%Vor%

Jetzt würden Sie es so verwenden:

%Vor%

Sie könnten einen Schritt weiter gehen und auch die anderen Abhängigkeiten createConnection und createChannel einfügen. Wenn Sie jedoch in der Lage wären, sie zu reinen Funktionen zu machen, wäre per Definition auch alles, was aus ihnen besteht, eine reine Funktion.

Was bedeutet das?

Wenn ich Ihnen zwei Funktionen gebe:

%Vor%

Oder verallgemeinert als Curry-Funktionen:

%Vor%

Sowohl add als auch multi werden als reine Funktionen betrachtet, dh wenn die gleiche Menge von Eingängen verwendet wird, ergibt sich die gleiche Ausgabe (lesen Sie: es gibt keine Nebenwirkungen). Sie werden dies auch als referentielle Transparenz (es lohnt sich ein Google) hören.

Da die beiden obigen Funktionen rein sind, können wir weiterhin behaupten, dass jede Zusammensetzung dieser Funktionen auch rein ist, d. h.

%Vor%

Auch ohne einen formellen Beweis sollte dies zumindest intuitiv klar sein, solange keine der Unterkomponenten Nebenwirkungen hinzufügt, sollte die Komponente als Ganzes keine Nebenwirkungen haben.

Da es sich auf Ihr Problem bezieht, sind createConnection und createChannel rein, dann gibt es eigentlich keine Notwendigkeit, sie zu verspotten, da ihr Verhalten funktional ist (im Gegensatz zu intern state driven). Sie können sie unabhängig testen, um zu überprüfen, ob sie wie erwartet funktionieren. Da sie jedoch rein sind, bleibt ihre Zusammensetzung (d. H.% Co_de%) ebenfalls rein.

Bonus

Diese Eigenschaft existiert auch in Observablen. Das heißt, die Zusammensetzung zweier reiner Observabler wird immer ein anderer reiner Observabler sein.

    
paulpdaniels 11.08.2017 18:44
quelle
0

Haben Sie darüber nachgedacht, in eines dieser spöttischen Pakete zu schauen? Insbesondere könnte rewire geeignet sein.

Proxyquire, rewire, SandboxedModule und Sinon: pros & amp; Nachteile

    
markrian 11.08.2017 13:57
quelle