2015-06-03 12 views
19

Rechnung Nehmen Sie das folgende Beispiel Javascript-Code unten:, wie Unit-Test-Ausgabe der Konsole mit Mokka auf NodeJS

function privateFunction (time) { 
    if (time < 12) { console.log('Good morning'); } 
    if (time >= 12 && time <19) { console.log('Good afternoon'); } 
    else { console.log('Good night!'); } 
}; 

Wie soll ich Unit-Test, dass auf NodeJS mit Mokka (und möglicherweise sinonjs) zu bemerken, dass dies eine private Funktion, die in einem Modul aufgerufen wird? Ich muss das Argument übergeben und prüfen, ob die Funktion das Richtige an der Konsole protokolliert.

Kann ich das gleiche mit console.warn und console.error machen?

Antwort

26

Ich bevorzuge mocha-sinon über "plain" sinon, weil es sich gut mit Mocha integriert.

Beispiel:

var expect = require('chai').expect; 
require('mocha-sinon'); 

// Function to test, can also be in another file and as long as it's 
// being called through some public interface it should be testable. 
// If it's not in any way exposed/exported, testing will be problematic. 
function privateFunction (time) { 
    if (time < 12) { console.log('Good morning'); } 
    if (time >= 12 && time <19) { console.log('Good afternoon'); } 
    else { console.log('Good night!'); } 
} 

describe('privateFunction()', function() { 

    beforeEach(function() { 
    this.sinon.stub(console, 'log'); 
    }); 

    it('should log "Good morning" for hours < 12', function() { 
    privateFunction(5); 
    expect(console.log.calledOnce).to.be.true; 
    expect(console.log.calledWith('Good morning')).to.be.true; 
    }); 

    it('should log "Good afternoon" for hours >= 12 and < 19', function() { 
    privateFunction(15); 
    expect(console.log.calledOnce).to.be.true; 
    expect(console.log.calledWith('Good afternoon')).to.be.true; 
    }); 

    it('should log "Good night!" for hours >= 19', function() { 
    privateFunction(20); 
    expect(console.log.calledOnce).to.be.true; 
    expect(console.log.calledWith('Good night!')).to.be.true; 
    }); 

}); 

Ein potenzielles Problem: einige Mocha Reporter verwenden console.log als gut, so dass die Tests, die es Stummel kann keine Ausgabe ergeben.

Es gibt einen Workaround, aber es ist auch nicht ideal, weil es die Mocha-Ausgabe mit der Ausgabe von privateFunction() durchsetzt. Wenn das kein Problem, ersetzen beforeEach() mit diesem:

beforeEach(function() { 
    var log = console.log; 
    this.sinon.stub(console, 'log', function() { 
    return log.apply(log, arguments); 
    }); 
}); 
+2

Wenn Sie Spion statt Stub verwenden dann die Abhilfe ist, nicht benötigt. – TMG

+0

@TMG Ich beginne mich tatsächlich zu fragen, ob die Problemumgehung keine Probleme mit Aufrufen von 'console.log()' verursacht, die von Reportern gemacht werden, die die Anrufzahl des Stubs/Spions stören. Wahrscheinlich nicht, weil ich denken würde, dass Reporter erst berichten, nachdem der Test gelaufen ist. In jedem Fall ist die Verwendung eines Spions eine bessere Lösung. – robertklep

2

ignoriert die Tatsache, dass es sich um eine private Funktion ist, ich ein paar Schritte unternehmen würde; Refactor mein Code für eine bessere Trennung von Bedenken, und nutzen Sie diese Trennung mit Test-Doppelgänger.

  • nehmen alle Nebenwirkungen außerhalb ihrer eigenen Module (die Nebenwirkung ist hier auf der Konsole zu schreiben):

    out.js

    function log (message) { 
        console.log(message); 
    }; 
    
    module.exports = {log}; 
    

    app.js

    const {log} = require('out'); 
    
    function greeter (time) { 
        if (time < 12) { 
        log('Good morning'); 
        } 
        if (time >= 12 && time < 19) { 
        log('Good afternoon'); 
        } else { 
        log('Good night!'); 
        } 
    }; 
    
    module.exports = {greeter}; 
    
  • einig Modul-Proxy/Spion, wie proxyquire verwenden, um den ganzen herausen Schriftsteller zu ersetzen, wenn Tests:

    app.spec.js

    describe('output writers', function(){ 
    
        const fakeOut = { 
        log: sinon.spy(), 
        }; 
    
        const app = proxyquire('./app', { 
        'out': fakeOut 
        }); 
    
        it('should log to the fake out', function(){ 
        app.greeter(15); 
        assert(fakeOut.log.calledOnce); 
        }); 
    });