Come testare un modulo node.js che richiede altri moduli

Questo è un esempio banale che illustra il punto cruciale del mio problema:

var innerLib = require('./path/to/innerLib'); function underTest() { return innerLib.doComplexStuff(); } module.exports = underTest; 

Sto cercando di scrivere un test unitario per questo codice. Come posso innerLib giro il requisito per il innerLib senza innerLib giro la funzione di require tutto?

EDIT: Quindi questo sono io che sto cercando di prendere in giro il bisogno globale e scoprire che non funzionerà nemmeno per farlo:

 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; } }; 

Il problema è che la funzione di require all’interno del file underTest.js non è stata effettivamente presa in giro. Punta ancora alla funzione di require globale. Quindi sembra che posso solo prendere in giro la funzione di require all’interno dello stesso file che sto facendo il beffardo. Se utilizzo il global require di includere qualcosa, anche dopo aver sovrascritto la copia locale, i file richiesti avranno ancora il riferimento globale require .

    Tu puoi ora!

    Ho pubblicato proxyquire che si occuperà di sovrascrivere il fabbisogno globale all’interno del modulo durante il test.

    Ciò significa che non è necessario apportare modifiche al codice per iniettare mock per i moduli richiesti.

    Proxyquire ha un’API molto semplice che consente di risolvere il modulo che si sta tentando di testare e di passare simulazioni / stub per i moduli richiesti in un semplice passaggio.

    @Raynos ha ragione che tradizionalmente dovevi ricorrere a soluzioni non molto ideali per ottenerlo o fare invece uno sviluppo dal basso verso l’alto

    Quale è il motivo principale per cui ho creato proxyquire – per consentire lo sviluppo guidato da test top-down senza problemi.

    Dai un’occhiata alla documentazione e agli esempi per valutare se soddisferà le tue esigenze.

    Un’opzione migliore in questo caso è di simulare i metodi del modulo che viene restituito.

    Nel bene o nel male, la maggior parte dei moduli node.js sono singleton; due pezzi di codice che richiedono () lo stesso modulo ottiene lo stesso riferimento a quel modulo.

    Puoi sfruttare questo e usare qualcosa come sinon per deridere gli oggetti che sono richiesti. il test di moka segue:

     // in your testfile var innerLib = require('./path/to/innerLib'); var underTest = require('./path/to/underTest'); var sinon = require('sinon'); describe("underTest", function() { it("does something", function() { sinon.stub(innerLib, 'toCrazyCrap', function() { // whatever you would like innerLib.toCrazyCrap to do under test }); underTest(); sinon.assert.calledOnce(innerLib.toCrazyCrap); // sinon assertion innerLib.toCrazyCrap.restore(); // restore original functionality }); }); 

    Sinon ha una buona integrazione con chai per fare asserzioni, e ho scritto un modulo per integrare sinon con mocha per facilitare la pulizia di spie / stub (per evitare l’inquinamento del test).

    Nota che underTest non può essere deriso allo stesso modo, dato che underTest restituisce solo una funzione.

    Io uso mock-require . Assicurati di definire i tuoi mock prima di require il modulo da testare.

    Puoi usare la libreria di mockery :

     describe 'UnderTest', -> before -> mockery.enable( warnOnUnregistered: false ) mockery.registerMock('./path/to/innerLib', { doComplexStuff: -> 'Complex result' }) @underTest = require('./path/to/underTest') it 'should compute complex value', -> expect(@underTest()).to.eq 'Complex result' 

    Non puoi Devi build la tua suite di test unitaria in modo che i moduli più bassi vengano testati per primi e che i moduli di livello superiore che richiedono moduli vengano successivamente testati.

    Devi anche assumere che qualsiasi codice di terze parti e node.js stesso sia ben testato.

    Presumo che nel prossimo futuro vedrai arrivare quadri beffardi che sovrascrivono i global.require

    Se è necessario iniettare una simulazione, è ansible modificare il codice per esporre l’ambito modulare.

     // underTest.js var innerLib = require('./path/to/innerLib'); function underTest() { return innerLib.toCrazyCrap(); } module.exports = underTest; module.exports.__module = module; // test.js function test() { var underTest = require("underTest"); underTest.__module.innerLib = { toCrazyCrap: function() { return true; } }; assert.ok(underTest()); } 

    Si tenga presente che questo espone il .__module nella propria API e che qualsiasi codice può accedere a un ambito modulare a proprio rischio.

    La derisione require mi sembra un brutto scherzo. Cercherò personalmente di evitarlo e di rifattorizzare il codice per renderlo più testabile. Esistono vari approcci per gestire le dipendenze.

    1) passare le dipendenze come argomenti

     function underTest(innerLib) { return innerLib.doComplexStuff(); } 

    Ciò renderà il codice universalmente testabile. Il rovescio della medaglia è che è necessario passare le dipendenze, il che può rendere il codice più complicato.

    2) implementare il modulo come class, quindi utilizzare metodi / proprietà di class per ottenere le dipendenze

    (Questo è un esempio forzato, in cui l’uso della class non è ragionevole, ma trasmette l’idea) (ES6 esempio)

     const innerLib = require('./path/to/innerLib') class underTestClass { getInnerLib () { return innerLib } underTestMethod () { return this.getInnerLib().doComplexStuff() } } 

    Ora puoi facilmente getInnerLib metodo getInnerLib per testare il tuo codice. Il codice diventa più dettagliato, ma anche più facile da testare.