2013-08-30 15 views
11

Sto costruendo un modulo di registrazione per la mia app Web in nodejs. Mi piacerebbe essere in grado di testare usando mocha che il mio modulo restituisca i messaggi corretti allo terminal. Mi sono guardato intorno ma non ho trovato nessuna soluzione ovvia per verificarlo. Ho trovatoUscita applicazione monitor Mocha

process.stdout.on('data', function(){}) 

ma non sono riuscito a farlo funzionare. Qualcuno ha qualche consiglio?

risposta

12

process.stdout non emetterà mai eventi 'data' perché non è un flusso leggibile. Puoi leggere tutto ciò nello node stream documentation, se sei curioso.

Per quanto ne so, il modo più semplice per agganciare o acquisire process.stdout o process.stderr è sostituire process.stdout.write con una funzione che fa ciò che si desidera. Super hacky, lo so, ma in uno scenario di test è possibile utilizzare prima e dopo i ganci per assicurarsi che venga sganciato, quindi è più o meno innocuo. Poiché scrive comunque nel flusso sottostante, non è la fine del mondo se non lo si disfa comunque.

function captureStream(stream){ 
    var oldWrite = stream.write; 
    var buf = ''; 
    stream.write = function(chunk, encoding, callback){ 
    buf += chunk.toString(); // chunk is a String or Buffer 
    oldWrite.apply(stream, arguments); 
    } 

    return { 
    unhook: function unhook(){ 
    stream.write = oldWrite; 
    }, 
    captured: function(){ 
     return buf; 
    } 
    }; 
} 

Si può usare nei test di moka in questo modo:

describe('console.log', function(){ 
    var hook; 
    beforeEach(function(){ 
    hook = captureStream(process.stdout); 
    }); 
    afterEach(function(){ 
    hook.unhook(); 
    }); 
    it('prints the argument', function(){ 
    console.log('hi'); 
    assert.equal(hook.captured(),'hi\n'); 
    }); 
}); 

Ecco un avvertimento: i giornalisti moca stampare sullo standard output. Non lo fanno, per quanto ne so, farlo mentre le funzioni di esempio (it('...',function(){})) sono in esecuzione, ma è possibile che si verifichino dei problemi se le funzioni di esempio sono asincrone. Vedrò se riesco a trovare di più su questo.

11

Ho tentato la risposta di jjm e ho avuto problemi che sospetto fosse dovuto al mio comportamento asincrono dei miei programmi.

Ho trovato una soluzione tramite un cli su github che utilizza la libreria sinon.

un codice di esempio per prova:

/* jshint node:true */ 
module.exports = Test1; 

function Test1(options) { 
    options = options || {}; 
} 


Test1.prototype.executeSync = function() { 
    console.log("ABC"); 
    console.log("123"); 
    console.log("CBA"); 
    console.log("321"); 
}; 

Test1.prototype.executeASync = function(time, callback) { 
    setTimeout(function() { 
    console.log("ABC"); 
    console.log("123"); 
    console.log("CBA"); 
    console.log("321"); 
    callback(); 
    }, time); 
}; 

E la moka prove:

/* jshint node:true */ 
/* global describe:true, it:true, beforeEach:true, afterEach:true, expect:true */ 

var assert = require('chai').assert; 
var expect = require('chai').expect; 
var sinon = require("sinon"); 

var Test1 = require("../test"); 

var test1 = null; 

describe("test1", function() { 
    beforeEach(function() { 
    sinon.stub(console, "log").returns(void 0); 
    sinon.stub(console, "error").returns(void 0); 
    test1 = new Test1(); 
    }); 

    afterEach(function() { 
    console.log.restore(); 
    console.error.restore(); 
    }); 

    describe("executeSync", function() { 
    it("should output correctly", function() { 
     test1.executeSync(); 

     assert.isTrue(console.log.called, "log should have been called."); 
     assert.equal(console.log.callCount, 4); 
     assert.isFalse(console.log.calledOnce); 
     expect(console.log.getCall(0).args[0]).to.equal("ABC"); 
     expect(console.log.getCall(1).args[0]).to.equal("123"); 
     expect(console.log.args[2][0]).to.equal("CBA"); 
     expect(console.log.args[3][0]).to.equal("321"); 
    }); 
    }); 

    describe("executeASync", function() { 
    it("should output correctly", function(done) { 
     test1.executeASync(100, function() { 
     assert.isTrue(console.log.called, "log should have been called."); 
     assert.equal(console.log.callCount, 4); 
     assert.isFalse(console.log.calledOnce); 
     expect(console.log.getCall(0).args[0]).to.equal("ABC"); 
     expect(console.log.getCall(1).args[0]).to.equal("123"); 
     expect(console.log.args[2][0]).to.equal("CBA"); 
     expect(console.log.args[3][0]).to.equal("321"); 
     done(); 
     }); 

    }); 
    }); 
}); 

sto fornendo quanto sopra come dimostra lavorare con le chiamate asincrone, si occupa sia della console e l'errore uscita e il metodo di ispezione è più utile.

Devo notare che ho fornito due metodi per ottenere ciò che è stato passato alla console, console.log.getCall(0).args[0] e console.log.args[0][0]. Il primo parametro è la riga scritta sulla console. Sentiti libero di usare ciò che pensi sia appropriato.

+2

Questa sembra la risposta migliore se non altro perché sfrutta il comune schema di Sinone e quindi è probabilmente più immediatamente comprensibile che cercare di acquisire process.stdout o qualsiasi altra cosa. Potrei essere solo me, però ... – aendrew

+0

test-console è una libreria leggera che fa ciò di cui stai parlando @endend. Vedi la mia risposta elencata qui – ianstarz

2

Altre due librerie che aiutano con questo sono test-console e intercept-stdout Non ho usato intercept-stdout, ma ecco come si può fare con test-console.

var myAsync = require('my-async'); 
var stdout = require('test-console').stdout; 

describe('myAsync', function() { 
    it('outputs something', function(done) { 
    var inspect = stdout.inspect(); 

    myAsync().then(function() { 
     inspect.restore(); 
     assert.ok(inspect.output.length > 0); 
     done(); 
    }); 
    }); 
}); 

Nota: È necessario utilizzare asincrona API di Mocha. Nessuna chiamata done() ingerirà il messaggio di test di mocha.