在带有存根功能的测试中没有捕获事件

时间:2013-08-09 08:28:51

标签: node.js mocha sinon chai

我遇到了一个我无法解决的问题。我发出的事件没有在我的测试中被捕获。 以下是代码(event.js):

var util = require('util'),
    proc = require('child_process'),
    EventEmitter = require('events').EventEmitter;

var Event = function() {
    var _self = this;
    proc.exec('ls -l', function(error, stdout, stderr) {
        _self.emit('test');
        console.log('emitted');
    });
};
util.inherits(Event, EventEmitter);

module.exports = Event;

相应的测试:

var proc = require('child_process'),
    sinon = require('sinon'),
    chai = require('chai'),
    expect = chai.expect,
    Event = require('./event'),
    myEvent, exec;

var execStub = function() {
    var _self = this;
    return sinon.stub(proc, 'exec', function(cmd, callback) {
        _self.cmd = cmd;
        console.log(cmd);
        callback();
    });
};

describe('Event', function() {
    beforeEach(function(){
        exec = execStub();
    });

    afterEach(function(){
        exec.restore();
    });

    it('Event should be fired', function(done) {
        myEvent = new Event();
        myEvent.on('test', function() {
            expect(exec.cmd).to.equal('ls -l');
            done();
        });
    });
});

现在,我看到的是:

  • 事件实际上是在console.log('emitted');发生后的测试期间发出的
  • exec发生以来console.log(cmd);函数实际上已存根

但测试失败并超时,并显示错误消息:

~ % mocha --timeout 15000 -R spec event.test.js


  Event
    ◦ Event should be fired: ls -l
emitted
    1) Event should be fired


  0 passing (15 seconds)
  1 failing

  1) Event Event should be fired:
     Error: timeout of 15000ms exceeded
      at null.<anonymous> (/usr/lib/node_modules/mocha/lib/runnable.js:165:14)
      at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

如果我从测试中删除存根,测试运行正常。如果我增加超时,我仍然有同样的问题。

知道我做错了什么?

此致

1 个答案:

答案 0 :(得分:2)

您的存根更改了process.exec()的同步/异步方面。

内部Node的实现保证了回调总是在事件循环的下一轮中运行:

myEvent = new Event(); // calls process.exec
myEvent.on('test', function() {
    expect(exec.cmd).to.equal('ls -l');
    done();
});
// process.exec callback will be called after all this code is executed

您的存根正在立即调用回调:

myEvent = new Event(); // calls process.exec
// process.exec callback is called immediately
// test event is emitted before listeners are attached
myEvent.on('test', function() {
  expect(exec.cmd).to.equal('ls -l');
  done();
});

解决方案是process.nextTick()

var execStub = function() {
  var _self = this;
  return sinon.stub(proc, 'exec', function(cmd, callback) {
      _self.cmd = cmd;
      console.log(cmd);
      process.nextTick(callback);
  });
};

您的测试还有另一个问题:exec存根回调中的_self指的是全局对象,您将值保存到global.cmd。您希望以后在测试中使用exec.cmd中的值。

这是最后的&amp;固定版execStub

var execStub = function() {
    var _self = sinon.stub(proc, 'exec', function(cmd, callback) {
        _self.cmd = cmd;
        console.log(cmd);
        process.nextTick(callback);
    });
    return _self;
};

有关回调异步性的更多信息,请参阅此post