Dies ist ein triviales Beispiel, das den Kern meines Problems veranschaulicht:
var innerLib = require('./path/to/innerLib');
function underTest() {
return innerLib.doComplexStuff();
}
module.exports = underTest;
Ich versuche, einen Komponententest für diesen Code zu schreiben. Wie kann ich die Anforderung für die innerLib
verspotten, ohne die require
Funktion vollständig zu verspotten ?
Ich versuche also, das Globale zu verspotten require
und herauszufinden, dass es nicht einmal funktioniert, das zu tun:
var path = require('path'),
vm = require('vm'),
fs = require('fs'),
indexPath = path.join(__dirname, './underTest');
var globalRequire = require;
require = function(name) {
console.log('require: ' + name);
switch(name) {
case 'connect':
case indexPath:
return globalRequire(name);
break;
}
};
Das Problem ist, dass die require
Funktion in der underTest.js
Datei tatsächlich nicht verspottet wurde. Es zeigt immer noch auf die globale require
Funktion. Es scheint also, dass ich die require
Funktion nur in derselben Datei verspotten kann, in der ich mich verspotte. Wenn ich die globale Datei verwende require
, um etwas einzuschließen, haben die erforderlichen Dateien auch nach dem Überschreiben der lokalen Kopie noch die globale require
Referenz.
quelle
global.require
. Variablen, auf diemodule
standardmäßig geschrieben wird, da Module einen Modulbereich haben.Antworten:
Du kannst jetzt!
Ich habe Proxyquire veröffentlicht, mit dem sichergestellt wird, dass die globalen Anforderungen in Ihrem Modul überschrieben werden, während Sie es testen.
Dies bedeutet, dass Sie keine Änderungen an Ihrem Code benötigen , um Mocks für die erforderlichen Module einzufügen.
Proxyquire verfügt über eine sehr einfache API, mit der Sie das Modul, das Sie testen möchten, in einem einfachen Schritt auflösen und Mocks / Stubs für die erforderlichen Module weitergeben können.
@Raynos hat Recht, dass man traditionell auf nicht sehr ideale Lösungen zurückgreifen musste, um dies zu erreichen, oder stattdessen eine Bottom-up-Entwicklung durchführen musste
Aus diesem Grund habe ich Proxyquire erstellt, um eine testgetriebene Top-Down-Entwicklung ohne Probleme zu ermöglichen.
Schauen Sie sich die Dokumentation und die Beispiele an, um festzustellen, ob sie Ihren Anforderungen entsprechen.
quelle
proxyquire
!In diesem Fall ist es besser, die Methoden des zurückgegebenen Moduls zu verspotten.
Ob gut oder schlecht, die meisten node.js-Module sind Singletons. Zwei Codeteile, für die () dasselbe Modul erforderlich ist, erhalten denselben Verweis auf dieses Modul.
Sie können dies nutzen und so etwas wie Sinon verwenden , um die benötigten Elemente zu verspotten. Mokka- Test folgt:
Sinon hat eine gute Integration mit Chai, um Aussagen zu machen, und ich habe ein Modul geschrieben, um Sinon mit Mokka zu integrieren , um die Reinigung von Spionen / Stummeln zu vereinfachen (um Testverschmutzung zu vermeiden).
Beachten Sie, dass underTest nicht auf die gleiche Weise verspottet werden kann, da underTest nur eine Funktion zurückgibt.
Eine andere Möglichkeit ist die Verwendung von Jest Mocks. Folgen Sie auf ihrer Seite
quelle
require('some_module')
Ihr gesamter Code dasselbe Objekt zurück, wenn Sie , da Ihr gesamter Code dasselbe Verzeichnis node_modules verwendet. Zweitens verschmilzt der Artikel den Namespace mit Singletons, was irgendwie orthogonal ist. Drittens ist dieser Artikel verdammt alt (was node.js betrifft), sodass das, was damals möglicherweise gültig war, jetzt möglicherweise nicht mehr gültig ist.innerLib.toCrazyCrap.restore()
sinub neu starten oder sinon aufrufen, übersinon.stub(innerLib, 'toCrazyCrap')
das Sie das Verhalten des Stubs ändern können :innerLib.toCrazyCrap.returns(false)
. Außerdem scheint die Neuverdrahtung derproxyquire
obigen Erweiterung sehr ähnlich zu sein .Ich benutze Mock-Require . Stellen Sie sicher, dass Sie Ihre Mocks definieren, bevor Sie
require
das zu testende Modul auswählen.quelle
Spott
require
fühlt sich für mich wie ein böser Hack an. Ich würde persönlich versuchen, dies zu vermeiden und den Code zu überarbeiten, um ihn testbarer zu machen. Es gibt verschiedene Ansätze, um mit Abhängigkeiten umzugehen.1) Übergeben Sie Abhängigkeiten als Argumente
Dadurch kann der Code universell getestet werden. Der Nachteil ist, dass Sie Abhängigkeiten weitergeben müssen, wodurch der Code komplizierter aussehen kann.
2) Implementieren Sie das Modul als Klasse und verwenden Sie dann Klassenmethoden / -eigenschaften, um Abhängigkeiten zu erhalten
(Dies ist ein erfundenes Beispiel, bei dem die Verwendung von Klassen nicht sinnvoll ist, aber die Idee vermittelt.) (ES6-Beispiel)
Jetzt können Sie die
getInnerLib
Methode zum Testen Ihres Codes einfach stubben . Der Code wird ausführlicher, aber auch einfacher zu testen.quelle
colors
String.prototype
Wenn Sie jemals einen Scherz benutzt haben, sind Sie wahrscheinlich mit der Scheinfunktion des Scherzes vertraut.
Mit "jest.mock (...)" können Sie einfach die Zeichenfolge angeben, die in einer require-Anweisung in Ihrem Code irgendwo vorkommen würde, und wenn ein Modul mit dieser Zeichenfolge benötigt wird, wird stattdessen ein Scheinobjekt zurückgegeben.
Beispielsweise
würde alle Importe / Anforderungen von "firebase-admin" vollständig durch das Objekt ersetzen, das Sie von dieser "Factory" -Funktion zurückgegeben haben.
Nun, Sie können dies tun, wenn Sie Jest verwenden, da Jest eine Laufzeit für jedes Modul erstellt, das ausgeführt wird, und eine "Hooked" -Version von Requirement in das Modul einfügt, aber ohne Jest wäre dies nicht möglich.
Ich habe versucht, dies mit Mock-Require zu erreichen , aber für mich hat es bei verschachtelten Ebenen in meiner Quelle nicht funktioniert. Schauen Sie sich das folgende Problem auf Github an: Mock- Require wird nicht immer mit Mocha aufgerufen .
Um dies zu beheben, habe ich zwei npm-Module erstellt, mit denen Sie das erreichen können, was Sie wollen.
Sie benötigen ein Babel-Plugin und einen Modul-Mocker.
Verwenden Sie in Ihrem .babelrc das babel-plugin-mock-require-Plugin mit folgenden Optionen:
und verwenden Sie in Ihrer Testdatei das jestlike-mock-Modul wie folgt:
Das
jestlike-mock
Modul ist immer noch sehr rudimentär und hat nicht viel Dokumentation, aber es gibt auch nicht viel Code. Ich schätze alle PRs für einen umfassenderen Funktionsumfang. Das Ziel wäre es, die gesamte Funktion "jest.mock" neu zu erstellen.Um zu sehen, wie jest implementiert, dass man den Code im "jest-runtime" -Paket nachschlagen kann. Siehe https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/index.js#L734 . Hier wird beispielsweise ein "Automock" eines Moduls generiert.
Hoffentlich hilft das ;)
quelle
Das kannst du nicht. Sie müssen Ihre Unit-Test-Suite so aufbauen, dass die niedrigsten Module zuerst getestet werden und die übergeordneten Module, für die Module erforderlich sind, anschließend getestet werden.
Sie müssen auch davon ausgehen, dass Code und node.js von Drittanbietern selbst gut getestet sind.
Ich nehme an, Sie werden in naher Zukunft spöttische Frameworks sehen, die überschreiben
global.require
Wenn Sie wirklich einen Mock einfügen müssen, können Sie Ihren Code ändern, um den modularen Bereich verfügbar zu machen.
Seien Sie gewarnt, dies wird
.__module
in Ihrer API angezeigt und jeder Code kann auf eigene Gefahr auf den modularen Bereich zugreifen.quelle
Sie können die Spottbibliothek verwenden:
quelle
Einfacher Code zum Verspotten von Modulen für Neugierige
Beachten Sie die Teile, an denen Sie die
require.cache
and-Note-require.resolve
Methode manipulieren , da dies die geheime Sauce ist.Verwenden Sie wie :
ABER ... Proxyquire ist ziemlich genial und du solltest das benutzen. Es hält Ihre Anforderungsüberschreibungen nur für Tests lokalisiert und ich kann es nur empfehlen.
quelle