Javascript sinon.js 间谍在一个测试用例中工作但在其他测试用例中不工作

Javascript sinon.js spy working in one test case but not in other

这是我的javascriptclass

var CommunicationInterface = inherit(Interface, {
  __constructor: function() {
    this.heartBeatDuration = 60 * 1000;
    this.client = null;
    this._isSetupped = false;
    this.__base();
  },

  setup: function() {
    // console.log('xmpp interface setup started');
    var _this = this;
    var deferred = Q.defer();

    if (this._isSetupped) {
      deferred.resolve();
      return deferred.promise;
    }

    CommConfig.get('params')
    .then(function(params) {
      _this.client = new Client({
        id: params.id + '@' + config('HOST'),
        password: params.password,
        host: config('HOST'),
        port: config('PORT'),
        reconnect: true
      });

      _this.client.on('online', _this.onOnline.bind(_this));

      setInterval(function() {
        _this.heartBeat.bind(_this)(params.id);
      }, _this.heartBeatDuration);

      _this._isSetupped = true;
      deferred.resolve();
    }, function(err){
      console.log(err);
    });

    return deferred.promise;
  },

  heartBeat: function(Id) {
    var stanza = this._makeMessage({
      'to': id + '@' + config('HOST'),
      'type': 'chat'
    }, '{}');
    console.log('foo');
    this.client.send(stanza);
    console.log('bar');
  },

  onOnline: function() {
    console.log('online');
    this.client.send('online');
    this.emitter.emit('online');
  },
});

测试代码为:

describe('CommunicationInterface', function() {
  var commInterface;
  var stubGetConfig, stubCommClient, stubCommClientConnect, spyCommClientSend;
  var clock;

  before(function () {
    var deferred = Q.defer();
    stubGetConfig = sinon.stub(CommConfig, 'get')
                      .withArgs('params')
                      .returns(deferred.promise);
    deferred.resolve({
      'id': 'test',
      'password': '123456',
    });
    stubCommClientConnect = sinon.stub(CommunicationInterface.Client.prototype,
                                       'connect');
    clock = sinon.useFakeTimers();
  });

  beforeEach(function () {
    commInterface = new CommunicationInterface();
    stubCommClient = sinon.spy(commInterface.client);
  });

  afterEach(function () {
    stubCommClientConnect.reset();
    stubGetConfig.reset();
    stubCommClient.reset();
    clock.restore();
  });

  it('test 1', function(done) {
    commInterface.setup()
    .done(function () {
      var spyCommClientSend = sinon.spy(commInterface.client, 'send');

      commInterface.client.emit('online');

      assert.isTrue(spyCommClientSend.calledOnce);
      assert.isTrue(spyCommClientSend.calledWithExactly('online'));
      done();
    });
  });

  it('test 2', function(done) {
    var spyHeartBeat = sinon.spy(commInterface.__proto__, 'heartBeat');

    commInterface.setup().done(function() {
      var spyCommClientSend = sinon.spy(commInterface.client, 'send');
      clock.tick(commInterface.heartBeatDuration + 10);

      assert.isTrue(spyHeartBeat.calledOnce);
      assert.isTrue(spyCommClientSend.called);

      spyHeartBeat.restore();
      done();
    });
  });
});

test 1 中的代码工作正常并且 spyCommClientSend 已正确创建,但 test 2 中的第二个断言失败并且 spyCommClientSend 未侦测到实际对象。

这可能是什么原因?

我确定正在调用 send 函数,因为它周围的两个 console.log 语句已打印出来。

乍一看,我认为问题在于你的间谍正在查看 commInterface.__proto__.heartBeat,这意味着你断言 CommunicationInterface 上的 heartBeat 方法 prototype 被调用。这不会发生,因为当你让 sinon 的时钟滴答作响时,heartBeat 调用是在你在 beforeEach 中创建的 commInterface 实例 上调用的。

这可能会通过实际监视 heartBeat 实例而不是原型来解决,如下所示:

var spyHeartBeat = sinon.spy(commInterface, 'heartBeat');

此外,我建议您通过将 afterEach 调用设置为 undefinednull 来清理 commInterface - 以确保您有一个每个测试用例都有 CommunicationInterface 的全新、完全干净的实例。

希望对您有所帮助!