如何在nodejs上使用mocha对控制台输出进行单元测试?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/30625404/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to unit test console output with mocha on nodejs?
提问by Kemel Zaidan
Take into account the following example Javascript code below:
考虑以下示例 Javascript 代码:
function privateFunction (time) {
if (time < 12) { console.log('Good morning'); }
if (time >= 12 && time <19) { console.log('Good afternoon'); }
else { console.log('Good night!'); }
};
How should I unit test that on nodejs using mocha (and possibly sinonjs), noticing that this is a private function called inside a module? I need to pass in the argument and check if the function is logging the right thing to the console.
我应该如何使用 mocha(可能还有 sinonjs)对 nodejs 进行单元测试,注意到这是一个在模块内部调用的私有函数?我需要传入参数并检查该函数是否将正确的内容记录到控制台。
Can I do the same with console.warnand console.error?
我可以用console.warnand做同样的事情console.error吗?
回答by robertklep
I prefer mocha-sinonover "plain" sinon because it integrates nicely with Mocha.
我更喜欢mocha-sinon“普通”的 sinon,因为它与 Mocha 很好地集成在一起。
Example:
例子:
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;
});
});
One potential issue: some Mocha reporters use console.logas well, so the tests that stub it may not yield any output.
一个潜在问题:一些 Mocha 记者也使用console.log,因此存根它的测试可能不会产生任何输出。
There's a workaround, but it's not ideal either because it will intersperse Mocha output with the output from privateFunction(). If that's not a problem, replace beforeEach()with this:
有一个解决方法,但它也不理想,因为它会将 Mocha 输出与privateFunction(). 如果这不是问题,请替换beforeEach()为:
beforeEach(function() {
var log = console.log;
this.sinon.stub(console, 'log', function() {
return log.apply(log, arguments);
});
});
回答by Eliran Malka
ignoring the fact that it's a private function, i would take a couple of steps; refactor my code for better separation of concerns, and utilise this separation with test doubles.
忽略它是一个私有函数的事实,我会采取几个步骤;重构我的代码以更好地分离关注点,并将这种分离用于测试替身。
take all the side effects outside to their own modules (the side effect here is writing to the console):
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};use some module proxy/spy, like proxyquireto replace the whole out writer when testing:
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); }); });
把所有的副作用都放到他们自己的模块中(这里的副作用是写到控制台):
输出.js
function log (message) { console.log(message); }; module.exports = {log};应用程序.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};在测试时使用一些模块代理/间谍,例如proxyquire来替换整个输出编写器:
应用规范.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); }); });
回答by Angelos Pikoulas
If your purpose is solelyto test console output, I would suggest instead of stubs / spies etc on method calls, to use something like:
如果您的目的仅仅是测试控制台输出,我建议您不要在方法调用上使用存根/间谍等,而是使用以下内容:
monitor stdout/stderr instead, you can use ideas from this gist

