Node.js 在使用存根函数的测试中未捕获事件

Node.js 在使用存根函数的测试中未捕获事件,node.js,mocha.js,sinon,chai,Node.js,Mocha.js,Sinon,Chai,我遇到了一个我不明白的问题。我发出的事件在测试中未捕获。 下面是以下代码(event.js): 以及相应的测试: var proc = require('child_process'), sinon = require('sinon'), chai = require('chai'), expect = chai.expect, Event = require('./event'), myEvent, exec; var execStub = funct

我遇到了一个我不明白的问题。我发出的事件在测试中未捕获。 下面是以下代码(
event.js
):

以及相应的测试:

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('emissed')发生
  • 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)
~%mocha--timeout 15000-R spec event.test.js
事件
◦ 应激发事件:ls-l
发出
1) 事件应该被触发
0传球(15秒)
1失败
1) 应在以下情况下触发事件:
错误:超过了15000ms的超时时间
在空。(/usr/lib/node_modules/mocha/lib/runnable.js:165:14)
at Timer.listOnTimeout[as onttimeout](timers.js:110:15)
如果我从测试中删除存根,测试运行正常。如果我增加超时,我仍然有同样的问题

知道我做错了什么吗


关于

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

内部节点的实现保证回调始终在事件循环的下一轮运行:

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()

您的测试还有另一个问题:
\u self
在exec存根回调中引用全局对象,您正在将值保存到
global.cmd
。您希望在以后的测试中在
exec.cmd
中有该值

以下是
execStub
的最终固定版本:

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

有关回调异步性的更多信息,请参见此部分。

Nice!伟大的教育答案!谢谢你花时间写下来!+1.答案很好。我有一个类似的问题,但我无法实现您的解决方案:(您能看看@Miroslav吗?谢谢!
var execStub = function() {
  var _self = this;
  return sinon.stub(proc, 'exec', function(cmd, callback) {
      _self.cmd = cmd;
      console.log(cmd);
      process.nextTick(callback);
  });
};
var execStub = function() {
    var _self = sinon.stub(proc, 'exec', function(cmd, callback) {
        _self.cmd = cmd;
        console.log(cmd);
        process.nextTick(callback);
    });
    return _self;
};