使用 rewire 和 sinon fakeTimer 时,顺序很重要吗?

When using rewire and sinon fakeTimer, order matters?

在测试具有定时间隔的设置时,我遇到了这个问题。

首先,我使用sinon's fakeTimers to create the right timed environment. rewire作为依赖注入库。

问题是,当涉及到重新布线时,有时应用虚假计时器似乎会失败,而在其他一些情况下它却可以正常工作。

请检查此设置:

test.js

'use strict';

require('should');
var sinon = require('sinon');
var rewire = require('rewire');

// this sample will not fall under the fake timer
var SampleGlobal = rewire('./testmodule');

describe('Sinon fake timer with rewirejs', function() {

    var clock;

    before(function() {
        clock = sinon.useFakeTimers();
    });

    after(function() {
        clock.restore();
    });

    it('work for locally rewired module', function() {

        var spy = sinon.spy();

        // locally inject-required module
        var Sample = rewire('./testmodule');

        new Sample().on('test', spy);

        spy.callCount.should.equal(0);

        clock.tick(5000);

        spy.callCount.should.equal(1);

    });

    it('break when rewired from global scope', function() {

        var spy = sinon.spy();

        // the module is globally inject-required
        new SampleGlobal().on('test', spy);

        spy.callCount.should.equal(0);

        clock.tick(5000);

        spy.callCount.should.equal(1);

    });

});

现在要包含间隔为:

的第二个模块

testmodule.js

'use strict';

var EventEmitter = require('events').EventEmitter;
var util = require('util');

function Sample() {

    this.h = setInterval(this.emit.bind(this, 'test'), 5000);

}

util.inherits(Sample, EventEmitter);

module.exports = Sample;

现在,如您所见,第二个测试失败了。这是使用模块的测试,因为它需要在脚本之上(也就是在全局范围内)。所以我怀疑这是因为 rewire 的工作方式以及安装 fakeTimers 的时间。

谁能详细解释一下?有没有一种方法可以在全局范围内使用需要注入的模块进行重新布线,或者我是否总是必须在较低级别重新布线它们?

rewire 预先添加一个 var 语句列表,以便将所有全局变量导入本地模块范围。因此,您可以在不影响其他模块的情况下更改全局变量。缺点是 global 属性的更改现在将被局部变量隐藏。

这些伪代码片段演示了问题:

没有重新布线

// Global scope
var setTimeout = global.setTimeout;

(function () {
    // Module scope. Node.js uses eval() and an IIFE to scope variables.
    ...
})()

重新布线

// Global scope
var setTimeout = global.setTimeout;

(function () {
    // Module scope.
    var setTimeout = global.setTimeout;
    ...
})()

您可以通过在 设置 sinon 的假计时器后重新布线 来解决您的问题。