2016-07-13 30 views
1

Ich habe ein Servicemodul, das als eine Funktion exportiert wird. Ich muss ein paar Dinge hineingeben, wie ein Konfigurationsobjekt, also muss es diese Struktur behalten. Ich versuche, eine Funktion aus dem Dienst auszugeben, kann es aber nicht herausfinden. In meiner App habe ich eine Funktion, die einen API-Aufruf macht, der beim Testen problematisch ist, also möchte ich es stubben. (Ich verstehe, ich muss meinen Test anders schreiben die Asynchron-Ausgabe zu handhaben)Wie kann ich eine Funktion/Eigenschaft eines Knotenmoduls, das mit sinon als Funktion exportiert wurde, verhöhnen?

// myService.js 
module.exports = function(config) { 
    function foo() { 
    returns 'bar'; 
    } 

    return { 
    foo: foo 
    }; 
}; 

// test.js 
var config = require('../../config'); 
var request = require('supertest'); 
var chai = require('chai'); 
var expect = chai.expect; 
var sinon = require('sinon'); 
var myService = require('./myService.js')(config); 

describe('Simple test', function(done) { 
    it('should expect "something else", function(done) { 
    var stub = sinon.stub(myService, 'foo').returns('something else'); 

    request(server) // this object is passed into my test. I'm using Express 
     .get('/testRoute') 
     .expect(200) 
     .expect(function(res) { 
     expect(res.body).to.equal('something else'); 
     stub.restore(); 
     }) 
     .end(done); 
    }); 
}); 

* /testRoute I set up as a simple GET route that simply returns the value from myService.foo() 

Die oben nicht funktioniert, und ich glaube, es ist die Art und Weise zu tun hat mein Service exportiert. Wenn ich den Dienst wie folgt schreibe, funktioniert der Stub gut.

module.exports = { 
    test: function() { 
    return 'something'; 
    } 
}; 

Aber auch hier muss ich der Lage sein, in Informationen an das Modul übergeben, so würde ich meine Module wie oben in der ursprünglichen Struktur zu halten. Gibt es eine Möglichkeit, eine Funktion von einem Modul auszustoßen, das auf diese Weise exportiert? Ich habe auch nach Proxyquire gesucht, bin mir aber nicht sicher, ob das die Antwort ist.

Antwort

2

Der Grund, warum Ihr Test Stub nicht funktioniert, ist, dass die Funktion foo jedes Mal erstellt wird, wenn der Modulinitialisierer aufgerufen wird. Wie Sie festgestellt haben, wenn Sie eine statische Methode für das Modul haben, können Sie stub.

Es gibt eine Vielzahl von Lösungen für dieses Problem - am einfachsten ist es, die Methode statisch verfügbar zu machen.

// myService.js 
module.exports = function(config) { 
    return { 
    foo: foo 
    }; 
}; 

var foo = module.exports.foo = function foo() { 
    return 'bar' 
} 

Es ist hässlich, aber funktioniert.

Was passiert, wenn die foo-Funktion eine Schließung für Variablen innerhalb des Service hat (weshalb sie in der Service-Initialisierer lebt). Dann müssen diese leider explizit übergeben werden.

// myService.js 
module.exports = function(config) { 
    return { 
    foo: foo 
    }; 
}; 

var foo = module.exports.foo = function(config) { 
    return function foo() { 
    return config.bar; 
    } 
} 

Jetzt können Sie das Modul sicher stubben.

Jedoch, wie Sie Stubbing sind, sollte als unsicher angesehen werden. Nur wenn Ihr Test perfekt funktioniert, wird der Stub aufgeräumt.

// We are not configuring the module, so the call with config is not needed 
var myService = require('./myService.js'); 

describe('Simple test', function(done) { 
    beforeEach(function() { 
    // First example, above 
    this.myStub = sinon.stub(myService, foo).returns('something else'); 
    // Second example, above 
    this.myStub = sinon.stub(myService, foo).returns(function() { 
     returns 'something else'; 
    }); 
    }); 

    afterEach(function() { 
    this.myStub.restore(); 
    }); 

    it('should expect "something else", function(done) { 
    request(server) // this object is passed into my test. I'm using Express 
     .get('/testRoute') 
     .expect(200) 
     .expect(function(res) { 
     expect(res.body).to.equal('something else'); 
     }) 
     .end(done); 
    }); 
}); 

Es gibt andere Optionen der Lage sein, um Abhängigkeiten Stummeln Dependency Injection mit: Sie sollten immer im before und after (oder beforeEach und afterEach) Vorrichtungen, wie Stummel. Ich empfehle Ihnen, Blick auf https://github.com/vkarpov15/wagner-core oder meine eigenen https://github.com/CaptEmulation/service-builder

+0

Vielen Dank, das macht Sinn. Ich versuche, in TDD einzutauchen und bessere Gewohnheiten aufzubauen, und das wird sicherlich helfen. Ich werde die Funktionen wie vorgeschlagen statisch darstellen. Vielen Dank auch für die Heads-up auf die Reinigung der Stub. Ich mache ein AfterJede, dass ich renne, um aufzuräumen :) Ich denke, ich hätte es in meine Frage aufnehmen sollen! – ahnkee

+0

Bitte denken Sie daran, meine Antwort zu akzeptieren, wenn es für Sie funktioniert – CaptEmulation

+0

Just did. War gerade dabei meinen letzten Kommentar zu beenden: p – ahnkee